セカンダリリストで一致するものが見つかった場合は、プライマリリストのフィールドを置き換えます。

セカンダリリストで一致するものが見つかった場合は、プライマリリストのフィールドを置き換えます。

約数千の行を含むリストがあり、各行には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。これらの要素もオーバーライドできます。
  • 各行に対して、awk2番目のブロックの文(最初の文はfound=0、最後の文はprint)が実行されます。
  • もしジェイ最初のフィールドはと同じですoldv。そのフィールドをで上書きして検索を停止newvします。たとえば、Bashのようなマルチレベルがawkないため、私たちは行ごとにリセットするというbreakヘルパー変数を使用します。found0
  • フィールドをオーバーライドするかどうかにかかわらず、print1行ずつ進みます。
  • このソリューションは、あなたが要求したよりも一般的です。各行の確認だけでこれを強化できます。最後のフィールド $(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のフラグはs4番目のフィールドを選択します。

答え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

関連情報