在保留格式的同时,用不同文件中的列替换文件中的列

时间:2013-12-12 19:24:22

标签: bash sed awk

我遇到了一个对高级shell用户来说似乎不太难的问题。这是问题所在。

我有2个文件:

File1的格式如下:

ALPH      1  M   GIF M   1      11.111  23.123  -4.412  1.00  0.00           A
ALPH      2  BA  GIF M   1      22.222  78.251  -6.215  2.00  0.00           B
ALPH      3  C   GIF M   1      22.223  46.321  -6.124  3.00  0.00           C
ALPH      4  D   GIF M   1      23.333  15.214  -6.125  4.00  0.00           D
ALPH      5  AB  GIF M   1      24.111  61.458  -8.214  5.00  0.00           E
ALPH      6  LM  GIF M   1      25.333  78.214  -9.321  6.00  0.00           F
ALPH      7  BA  GIF M   1      17.645  87.256  -9.365  7.00  0.00           G
ALPH      8  BA2 GIF M   1      14.125  19.365  -1.258  8.00  0.00           H
-
-

File2只有一列:

-0.14
-0.47
-0.58
-0.69
-0.25
-0.69
-0.12
-0.44

我想用File2中的唯一列替换File1中的第11列。我做了以下

paste File1 File2 | awk '{$11=$13;$13=""}1' > output

虽然它可以很好地替换列,但它会混淆我希望保留的File1的原始格式。正如您所看到的,File1的所有字段之间存在不同数量的空格,即使在替换$ 11之后我也希望保留这些空格。

我尝试了多种方法,包括columnprintf,但似乎都没有。也许我做错了什么。

有没有人知道如何使用awk或sed来达到理想的效果?

谢谢!

罗希特夏尔

6 个答案:

答案 0 :(得分:3)

当您为awk中的字段分配值时,它会使用OFS的当前值重新编译当前记录以分隔字段。要保留原始间距,则无法为字段指定新值。相反,您必须使用RE来描述在分配之前和之后要跳过的非空格/空格的数量。像这样取代字母" c" (第3个字段,因此数字" 2"下面是跳过的前导字段数),单词" BOB"使用GNU awk:

$ echo "a   b c    d e" |
gawk '{print gensub(/(([^[:space:]]+[[:space:]]+){2})[^[:space:]]+/,"\\1BOB","")}'
a   b BOB    d e

这会保留间距,因为您正在处理整个记录,而不仅仅是一个字段,因此awk不会重新编译记录。

因此,对于您的情况,它是:

$ cat file1
ALPH      1  M   GIF M   1      11.111  23.123  -4.412  1.00  0.00           A
ALPH      2  BA  GIF M   1      22.222  78.251  -6.215  2.00  0.00           B
ALPH      3  C   GIF M   1      22.223  46.321  -6.124  3.00  0.00           C
ALPH      4  D   GIF M   1      23.333  15.214  -6.125  4.00  0.00           D
ALPH      5  AB  GIF M   1      24.111  61.458  -8.214  5.00  0.00           E
ALPH      6  LM  GIF M   1      25.333  78.214  -9.321  6.00  0.00           F
ALPH      7  BA  GIF M   1      17.645  87.256  -9.365  7.00  0.00           G
ALPH      8  BA2 GIF M   1      14.125  19.365  -1.258  8.00  0.00           H
$          
$ cat file2
-0.14
-0.47
-0.58
-0.69
-0.25
-0.69
-0.12
-0.44
$ 
$ gawk 'NR==FNR{map[FNR]=$0; next} {print gensub(/(([^[:space:]]+[[:space:]]+){10})[^[:space:]]+/,"\\1" map[FNR],"")}' file2 file1
ALPH      1  M   GIF M   1      11.111  23.123  -4.412  1.00  -0.14           A
ALPH      2  BA  GIF M   1      22.222  78.251  -6.215  2.00  -0.47           B
ALPH      3  C   GIF M   1      22.223  46.321  -6.124  3.00  -0.58           C
ALPH      4  D   GIF M   1      23.333  15.214  -6.125  4.00  -0.69           D
ALPH      5  AB  GIF M   1      24.111  61.458  -8.214  5.00  -0.25           E
ALPH      6  LM  GIF M   1      25.333  78.214  -9.321  6.00  -0.69           F
ALPH      7  BA  GIF M   1      17.645  87.256  -9.365  7.00  -0.12           G
ALPH      8  BA2 GIF M   1      14.125  19.365  -1.258  8.00  -0.44           H

如果你没有gawk(对于gensub()),你可以使用match()来查找你关心的字段的开始位置,第二个匹配()用于结束的位置,以及明智的substr() s用新值替换它。

@GlennJackman在他的解决方案中提到了固定宽度字段。如果您拥有的是什么,可以使用GNU awks FIELDWIDTHS变量来指定每个字段的宽度,并使用它。有关详细信息,请参阅gawk手册。

答案 1 :(得分:2)

使用awk

awk 'FNR==NR {a[NR]=$0;next} {$11=a[FNR]}1' OFS="\t" a t
ALPH    1       M       GIF     M       1       11.111  23.123  -4.412  1.00    -0.14   A
ALPH    2       BA      GIF     M       1       22.222  78.251  -6.215  2.00    -0.47   B
ALPH    3       C       GIF     M       1       22.223  46.321  -6.124  3.00    -0.58   C
ALPH    4       D       GIF     M       1       23.333  15.214  -6.125  4.00    -0.69   D
ALPH    5       AB      GIF     M       1       24.111  61.458  -8.214  5.00    -0.25   E
ALPH    6       LM      GIF     M       1       25.333  78.214  -9.321  6.00    -0.69   F
ALPH    7       BA      GIF     M       1       17.645  87.256  -9.365  7.00    -0.12   G
ALPH    8       BA2     GIF     M       1       14.125  19.365  -1.258  8.00    -0.44   H
由于sub

的错误,

修改已恢复原始状态

答案 2 :(得分:2)

如果您需要保留固定宽度列,则可以使用子字符串:

cat file1
echo
awk '
    NR==FNR {v[FNR]=$1; next}
    {print substr($0,1,62) sprintf("%-15s", v[FNR]) substr($0,78)}
' file2 file1
ALPH      1  M   GIF M   1      11.111  23.123  -4.412  1.00  0.00           A
ALPH      2  BA  GIF M   1      22.222  78.251  -6.215  2.00  0.00           B
ALPH      3  C   GIF M   1      22.223  46.321  -6.124  3.00  0.00           C
ALPH      4  D   GIF M   1      23.333  15.214  -6.125  4.00  0.00           D
ALPH      5  AB  GIF M   1      24.111  61.458  -8.214  5.00  0.00           E
ALPH      6  LM  GIF M   1      25.333  78.214  -9.321  6.00  0.00           F
ALPH      7  BA  GIF M   1      17.645  87.256  -9.365  7.00  0.00           G
ALPH      8  BA2 GIF M   1      14.125  19.365  -1.258  8.00  0.00           H

ALPH      1  M   GIF M   1      11.111  23.123  -4.412  1.00  -0.14          A
ALPH      2  BA  GIF M   1      22.222  78.251  -6.215  2.00  -0.47          B
ALPH      3  C   GIF M   1      22.223  46.321  -6.124  3.00  -0.58          C
ALPH      4  D   GIF M   1      23.333  15.214  -6.125  4.00  -0.69          D
ALPH      5  AB  GIF M   1      24.111  61.458  -8.214  5.00  -0.25          E
ALPH      6  LM  GIF M   1      25.333  78.214  -9.321  6.00  -0.69          F
ALPH      7  BA  GIF M   1      17.645  87.256  -9.365  7.00  -0.12          G
ALPH      8  BA2 GIF M   1      14.125  19.365  -1.258  8.00  -0.44          H

答案 3 :(得分:2)

这可能适合你(GNU sed):

sed = file2 | sed -r '$!N;s|(.*)\n(.*)|\1s/\\S+/\2/11|' | sed -rf - file1

答案 4 :(得分:1)

Pure awk解决方案:

awk 'FNR==NR{a[NR]=$0;next} {sub($11, a[FNR])}1' file2 file1
ALPH      1  M   GIF M   1      11.111  23.123  -4.412  1.00  -0.14           A
ALPH      2  BA  GIF M   1      22.222  78.251  -6.215  2.00  -0.47           B
ALPH      3  C   GIF M   1      22.223  46.321  -6.124  3.00  -0.58           C
ALPH      4  D   GIF M   1      23.333  15.214  -6.125  4.00  -0.69           D
ALPH      5  AB  GIF M   1      24.111  61.458  -8.214  5.00  -0.25           E
ALPH      6  LM  GIF M   1      25.333  78.214  -9.321  6.00  -0.69           F
ALPH      7  BA  GIF M   1      17.645  87.256  -9.365  7.00  -0.12           G
ALPH      8  BA2 GIF M   1      14.125  19.365  -1.258  8.00  -0.44           H

答案 5 :(得分:0)

或者使用剪切:

cat file1 | cut -c 1-61 > section1
cat file1 | cut -c 67-80 > section2
paste section1 file2 section2 > output

文件格式看起来像一个 pdb 文件,字段之间的空白无关紧要,重要的是字段宽度