我有一个以下格式的文件:
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
在任何情况下都应该有一个。