約数千の行を含むリストがあり、各行には4〜5個のフィールドが含まれています。複数の行と1つのフィールドのみを持つ2番目のリストもあります。どちらのリストも変数に保存されます。
最初のリスト:
item_1 something something value something
item_2 something something value
item_3 something something value something
item_4 something something value something
...
item_2155 something something value
item_2156 something something value something
2番目のリスト:
item_3
item_2155
望ましい最終結果:
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something
whileループでsedを使用しようとしています。ある程度動作しますが、この方法は繰り返されるたびにリストをそれ自体に追加します。私もawkがより良い解決策だと思います。
#!/bin/bash
MYHUGELIST=$(command)
MYSHORTLIST=$(command)
while read -r line ; do
sed "/^$line /s/1of3-possible-matches/newvalue/;/^$line /s/2of3-possible-matches/newvalue/;/^$line /s/3of3-possible-matches/newvalue/" <<< "$MYHUGELIST"
done <<< "$MYSHORTLIST"
答え1
awk
使用する代わりに使用を検討するソリューションがありますかsed
?の場合、
#!/bin/bash
read -r -d '' shortlistOneString < shortlist.txt
awk -v oldv=value -v newv=new_value -v s="$shortlistOneString" \
'BEGIN {n=split(s,a,"\n")} { \
found=0; \
for (i=1; ! found && i<=n; ++i) { \
if (a[i] == $1) { \
for (j=2; j<= NF; ++j) { \
if ($j == oldv) { \
$j = newv; found=1; break }}}}; \
print}' longlist.txt
ノート
- 改行文字とすべての内容をシェル変数
shortlist.txt
として読み込みますshortlistOneString
。 BEGIN
ブロックでは、 の値をという配列に"$shortlistOneString"
分割しますa
。この配列には、n
私たちがアクセスできる要素があります。私番目の要素はと同じですa[i]
。このブロックは、awk
入力が正しい前に一度だけ実行されます。- それ自体では、
awk
各行はすべての入力行に対して特別な保持配列に構文解析され、この配列にはNF
私たちがアクセスできる要素があります。ジェイ最初の要素は付属しています$j
。これらの要素もオーバーライドできます。 - 各行に対して、
awk
2番目のブロックの文(最初の文はfound=0
、最後の文はprint
)が実行されます。 - もしジェイ最初のフィールドはと同じです
oldv
。そのフィールドをで上書きして検索を停止newv
します。たとえば、Bashのようなマルチレベルがawk
ないため、私たちは行ごとにリセットするというbreak
ヘルパー変数を使用します。found
0
- フィールドをオーバーライドするかどうかにかかわらず、
print
1行ずつ進みます。 - このソリューションは、あなたが要求したよりも一般的です。各行の確認だけでこれを強化できます。最後のフィールド
$(NF)
そして2番目のフィールド$(NF-1)
;フィールド位置を$5
別々にハードコーディングすることもできます$4
。
答え2
sed を使用して awk スクリプトを実行できます
cmd1 | awk "$(cmd2 | sed -e 's:.*:/^& /{\$4=\"new_value\"}:')1"
どこ
cmd1
生産する$MYHUGELIST
cmd2
生産する$MYSHORTLIST
- の各行は
$MYSHORTLIST
次のとおりです。/^item_N /{$4="new_value"}
- awkスクリプトの終了
1
により、現在の行が印刷されます。 $
"
必要に応じて文字をエスケープします。
または sed のみ、
cmd1 | sed -e "$(cmd2 | sed -e 's:.*:/^& /s/[^ ][^ ]*/new_value/4:')"
ここで、コマンド4
のフラグはs
4番目のフィールドを選択します。
答え3
必要なのは awk の簡単な呼び出しだけで、ループ、パイプ、その他のコマンドは必要ありません。
データがファイルにある場合:
$ awk 'NR==FNR{a[$1]; next} $1 in a{$4="new_value"} 1' secondFile firstFile
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something
またはデータが変数にある場合:
$ awk -v sec="$second" '
BEGIN{split(sec,tmp); for (i in tmp) a[tmp[i]]}
$1 in a{$4="new_value"} 1
' <<<"$first"
item_1 something something value something
item_2 something something value
item_3 something something new_value something
item_4 something something value something
...
item_2155 something something new_value
item_2156 something something value something