首页 > 解决方案 > How to replace a portion of file1 by a portion of file2 uing sed or awk, portion delineated by row and column no

问题描述

I have two files, say file1 and file2 and they are in the following format

file1:
many rows
36th rows
XX  1.1  1.2  9.9
YY  2.5  3.6  3.8

file2
several rows
9th row
5.5  6.6  9.8  T  T  T
5.4  5.6  7.8  T  T  T

What I want for the updated file1 is the following:

first row
XX  5.5  6.6  9.8
YY  5.4  5.6  7.8

I know I can replace lines if the string in file1 matches a string I provide by using this command

sed -i "s/1.1  1.2  9.9/5.5  6.6  9.8/" file1

However for this case, it should be much easier to replace the values using their row and column numbers. May I know how to go about doing this?

The actual files: File1:

&control
     calculation='scf'
     restart_mode='from_scratch'
     prefix='prefix1'
     pseudo_dir = '.'
     nstep = 2000,
     etot_conv_thr = 1.0E-6 ,
     forc_conv_thr = 1.0D-4,
     outdir = prefix1

/
 &system
    ibrav=0,
    nat=8,
    ntyp=3,
    ecutwfc = 60.0,   
    ecutrho = 600,
/
&electrons
    electron_maxstep = 250
    mixing_beta     = 0.1
    conv_thr        = 1.0d-10
/

CELL_PARAMETERS (angstrom)
     3.9746359870249388    0.0000000000000000    0.0000000000000000
     0.0000000000000000    7.5980663633997150    0.0000000000000000
     0.0000000000000000    0.0000000000000000   24.1776735510378913


ATOMIC_SPECIES
  I 126.90447d0 I.pbe-n-kjpaw_psl.1.0.0.UPF
  Nb 92.906400d0 Nb.pbe-spn-kjpaw_psl.1.0.0.UPF
  O 15.999400d0 O.pbe-n-kjpaw_psl.1.0.0.UPF

ATOMIC_POSITIONS {crystal}
Nb  0.7500000000000000  0.3084626380344986  0.5000000000000000
Nb  0.7500000000000000  0.8915373619655043  0.5000000000000000
I   0.7500000000000000  0.6000000000000014  0.5781487300676179
I   0.7500000000000000  0.1000000000000014  0.5953056146454921
I   0.7500000000000000  0.1000000000000014  0.4046943853545079
I   0.7500000000000000  0.6000000000000014  0.4218512699323820
O   0.2500000000000000  0.3124817357885405  0.5000000000000000
O   0.2500000000000000  0.8875182642114551  0.5000000000000000
K_POINTS {automatic}
12 6 1 0 0 0

This is file2:

Nb I O                                  
   1.00000000000000     
     3.9746359870249388    0.0000000000000000    0.0000000000000000
     0.0000000000000000    7.5980663633997150    0.0000000000000000
     0.0000000000000000    0.0000000000000000   24.1776735510378913
   Nb   I    O 
     2     4     2
Selective dynamics
Direct
  0.11  0.21  0.31   F   F   F
  0.12  0.22  0.32   F   F   F
  0.13  0.23  0.33   T   T   T
  0.14  0.24  0.34   T   T   T
  0.15  0.25  0.35   T   T   T
  0.16  0.26  0.36   T   T   T
  0.17  0.27  0.37   F   T   T
  0.18  0.28  0.38   F   T   T

I'm trying to replace the ATOMIC_POSITIONS portion of file1 (from row 37 column 2 to row 44 column4) with the bottom chunk of file2 (from row 10 column 1 to row 17 column 3) .

So the bottom of file1 should be something like this:

ATOMIC_POSITIONS {crystal}
Nb        0.11  0.21  0.31
Nb        0.12  0.22  0.32
I         0.13  0.23  0.33
I         0.14  0.24  0.34
I         0.15  0.25  0.35
I         0.16  0.26  0.36
O         0.17  0.27  0.37
O         0.18  0.28  0.38

K_POINTS {automatic}
12 6 1 0 0 0

标签: bashawksed

解决方案


EDIT2:由于OP现在提到了与以前不同的实际样本,所以现在添加。

awk '
FNR==NR{
  if(!NF){
     flag=""
  }
  if($0=="Direct"){
     flag=1
  }
  if(flag){
     array[++count]=$1 OFS $2 OFS $3
  }
  next
}
/ATOMIC_POSITIONS {crystal}/{
  found=1
}
!NF{
  found=count1=""
}
found{
  print $1"\t"array[++count1]
  next
}
1
'  Input_file2 Input_file1

如果对上面的结果感到满意,请附加> temp && mv temp Input_file1到上面。



编辑:由于 OP 澄清了问题,因此更多地知道来自源(Input_file2)的行号可能与目标(Input_file1)不同,所以假设我们有以下 Input_files。

awk -v source_row="10,11,12,13,14,15,16,17" -v target_row="37,38,39,40,41,42,43,44" '
BEGIN{
  split(source_row,array_source,",")
  num=split(target_row,array_target,",")
  for(i=1;i<=num;i++){
     replace_array[array_target[i]]
  }
}
FNR==NR{
  a[FNR]=$1 OFS $2 OFS $3
  next
}
(FNR in replace_array){
  print $1"\t"a[array_source[++count]]
  next
}
1
'  Input_file2   Input_file1

其中 variablessource_row用于 Input_file,我们需要从中获取值和变量target_row用于目标 Input_file 我们需要放置行的位置。

要将输出保存到 Input_file1,请在上述命令的最后附加> temp && mv temp Input_file1



如果您想用行号替换 Input_file1 中的行,请尝试以下操作。

awk 'FNR==NR{a[FNR]=$1 OFS $2 OFS $3;next} {print $1,a[FNR]}' Input_file2  Input_file1

输出如下。

XX b1 b2 b3
YY b4 b5 b6

推荐阅读