web-dev-qa-db-ja.com

別のフィールドの内容に基づいてファイル内の特定のフィールドを置き換える方法は?

次の形式のファイルがあります。

A 485C72F95C72E15C EXTERNAL
B CC32480A3247F84A SYSTEM
C EC2A63F12A63B76C EXTERNAL

変数「letter」の値を使用して最初の列に文字を指定し、2番目の列の値を変数「id」に指定した値に置き換えます。 3番目の列は、どんな場合でも異なる場合も一致する場合もあります。 1列目と2列目には、スペースや特殊文字は含まれません。

sedを使用しようとしましたが、私のsed-fuは強くありません。私はこれを思いつきました:

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

出力は次のとおりです。

A MYNEWIDSTRING EXTERNAL
B MYNEWIDSTRING SYSTEM
C EC2A63F12A63B76C EXTERNAL

Idは2行で置き換えられます。これは、元のid文字列の最後で「A」が一致したためと思われます。

sed -iを使用してファイルをインプレース編集することは知っていますが、コマンドはまだ少し危険なので、まだ編集していません。

どこで間違っていますか、または別の方法を使用する必要がありますか?

4
Arronical

Aが最初の文字の場合にのみ一致するように、アンカーします(^は行の先頭です):

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

ところで、変数をsedに渡したいが、強力な引用符が必要な場合は、変数の二重引用符を追加しながら引用符のオンとオフを切り替えることができます-lyいですが、おそらくベストプラクティス:

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

structured dataを扱うときはいつでも、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が必要です。

5
steeldriver