有条件地将 file1 的行替换为 file2 的相应行

有条件地将 file1 的行替换为 file2 的相应行

例如,我有两个文件:

文件1:

1
4
X
5
X
7

文件2:

2
3
5
X
X
1

我想将Xfile1 的 -lines 替换为 file2 中相应行中的内容:

结果:

1
4
5
5
X
7

我更喜欢使用 CLI 命令的解决方案,例如sed.

答案1

如果 file2 适合内存,那么您可以使用 awk。首先让它读取 file2,然后在处理 file1 时,如果看到“X”,则从 file2 数组中替换它:

$ awk 'NR == FNR { lines[NR]=$0; } NR != FNR { if ($0 == "X") print lines[FNR]; else print $0 }' file2 file1

重新格式化一下,就是:

$ awk 'NR == FNR { lines[NR]=$0; } 
       NR != FNR { if ($0 == "X") print lines[FNR]; 
                   else           print $0 
                 }' file2 file1

请注意,file2 是第一个文件名; file1 是第二个文件名。

答案2

$ paste file1 file2 | awk -F '\t' '$1 == "X" { $1 = $2 } { print $1 }'
1
4
5
5
X
7

paste命令将生成制表符分隔的输出

1       2
4       3
X       5
5       X
X       X
7       1

如果第一个字段是字符,则awk脚本只需将第一个制表符分隔字段设置为第二个字段的内容X,然后打印第一个(现在可能已修改)字段。

不同的方法由格伦·杰克曼推荐它不会修改传入的数据,而只是根据第一列中的数据选择要打印的字段:

$ paste file1 file2 | awk -F '\t' '{ print $1 == "X" ? $2 : $1 }'

使用 GNU sed

$ paste file1 file2 | sed -E -e '/^X/s/^[^\t]+\t//' -e 's/\t.*$//'
1
4
5
5
X
7

这两个sed表达式执行以下操作:

  1. 如果当前行以 开头X,则第一次替换将删除第一个制表符之前的所有内容(包括第一个制表符)。paste如果第一列是 ,这会有效地将输出的第二列移动到第一列X
  2. 第二个表达式删除制表符及其后面的任何内容。这会删除我们不感兴趣的数据。

答案3

用bash

while IFS= read -r -u3 f1; IFS= read -r -u4 f2; do
    [[ $f1 == X ]] && echo "$f2" || echo "$f1"
done 3<file1 4<file2

或者更一般地说,POSIX

while IFS= read -r f1 <&3; IFS= read -f f2 <&4; do
    [ "$f1" = X ] && echo "$f2" || echo "$f1"
done 3<file1 4<file2

相关内容