如何根据另一个字段的内容替换文件中的特定字段?

如何根据另一个字段的内容替换文件中的特定字段?

我有一个以下格式的文件:

A 485C72F95C72E15C EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

我想使用变量“letter”的值在第一列中提供字母,并用我在变量“id”中提供的值替换第二列中的值。第三列在任何情况下可能不同或不匹配。第一列和第二列永远不会包含空格或特殊字符。

我尝试过使用sed,但我的 sed-fu 不够强。我想出了这个:

letter=A
id=MYNEWIDSTRING
sed "/$letter /s/[^ ]*/$id/2"

输出为:

A MYNEWIDSTRING EXTERNAL
B MYNEWIDSTRING SYSTEM
C EC2A63F12A63B76C EXTERNAL

该 id 被替换为两行,我假设这是由于“A”在原始 id 字符串的末尾匹配。

我知道如何使用sed -i来就地编辑文件,但还没有这样做,因为我的命令仍然有点不可靠。

我哪里做错了,或者我应该使用不同的方法?

答案1

固定它(^是行的开头),以便A只有当它是第一个字符时才匹配:

$ letter=A; id=MYNEWIDSTRING; sed "/^$letter /s/[^ ]*/$id/2" file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

顺便说一句,如果您想传递变量sed但需要强引用,请记住您可以在为变量添加双引号时打开或关闭引用 - 很丑但可能是最佳做法:

sed '/^'"$letter"' /s/[^ ]*/'"$id"'/2'

答案2

无论何时你结构化的数据,我会选择awk或者perl而不是sed

例如

awk -v letter="A" -v id="MYNEWIDSTRING" '$1 == letter {$2=id}1' file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

或者

perl -alne '
  BEGIN{$letter = shift; $id = shift;} 
  print join " ", $F[0], $F[0] eq $letter ? $id : $F[1], @F[2..$#F]
' 'A' 'MYNEWIDSTRING' file

GNU awk 的较新版本有一个-i( --in-place) 标志;在其他版本中,您需要使用明确的临时文件;perl-i在任何情况下都应该有一个。

相关内容