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

Arr*_*cal 4 command-line bash sed text-processing

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

A 485C72F95C72E15C EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL
Run Code Online (Sandbox Code Playgroud)

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

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

letter=A
id=MYNEWIDSTRING
sed "/$letter /s/[^ ]*/$id/2"
Run Code Online (Sandbox Code Playgroud)

输出是:

A MYNEWIDSTRING EXTERNAL
B MYNEWIDSTRING SYSTEM
C EC2A63F12A63B76C EXTERNAL
Run Code Online (Sandbox Code Playgroud)

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

我知道用来sed -i就地编辑文件,但还没有这样做,因为我的命令仍然有点狡猾。

我哪里出错了,还是应该使用不同的方法?

Zan*_*nna 5

锚定它(^是行首),以便A只有在它是第一个字符时才匹配:

$ letter=A; id=MYNEWIDSTRING; sed "/^$letter /s/[^ ]*/$id/2" file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL
Run Code Online (Sandbox Code Playgroud)

顺便说一句,如果您想将变量传递给sed但需要强引用,请记住,您可以在为变量添加双引号的同时打开和关闭引用 - 丑陋但通常可能是最佳实践:

sed '/^'"$letter"' /s/[^ ]*/'"$id"'/2'
Run Code Online (Sandbox Code Playgroud)


ste*_*ver 5

每当您处理结构化数据时,我都会使用awkperl而不是sed.

例如

awk -v letter="A" -v id="MYNEWIDSTRING" '$1 == letter {$2=id}1' file
A MYNEWIDSTRING EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL
Run Code Online (Sandbox Code Playgroud)

或者

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

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