変数を正規表現としてawkする

変数を正規表現としてawkする

質問は本当に簡単です。私はすべての質問を読みましたが、まだ理解できません。私はこのような単純なファイルを持っています

$cat file1.txt
ALA
AJD
KSF

そして、awk で各値を正規表現として使用し、別のファイルから別のファイルに行を印刷するようにします。

$cat file2.txt
name,st,ed,le
ALA,10,12,12
ALA,2,5,4
ALA,6,5,8
AJD,5,8,7
KSF,5,8,7

私の脚本は

while read p;
awk -F"," 'NR==1{print $0}' file2.txt > $p.csv
awk -F"," '/$p/{print $0}' file2.txt >> $p.csv
done <file1.txt

望ましい出力は次のようになります。

$cat ALA.csv
name,st,ed,le
ALA,10,12,12
ALA,2,5,4
ALA,6,5,8
$cat AJD.csv
name,st,ed,le
AJD,5,8,7
$cat KSF.csv
name,st,ed,le
KSF,5,8,7

残念ながら、各ファイルにはヘッダーしか印刷されません。file1.txt から各値を手動で $p に置き換えて入力したところ、問題なく動作しました。問題は変数 $p が適切に解釈されていないことだと思います。引用符や二重引用符を使ってみました。また、見つけたさまざまな提案も試しましたが、どれもうまくいかないようです。

答え1

次の方法も考えられます:

awk "/$p/" file2.txt > "$p.csv"

それは殻を持っている拡大する$pに渡されるコード内のシェル変数の内容はawk、悪い習慣であり、基本的にコマンドインジェクションの脆弱性に相当します (たとえば、$pのような値の場合^/{system("reboot");/)。最善の方法は、シェル変数をそのまま awk に渡し、正規表現のマッチングに awk の演算子を使用することです。最善の方法は、環境変数との特殊配列~を使用することです。awkENVIRON

export P
while IFS= read -r P; do
  awk 'NR == 1 || $0 ~ ENVIRON["P"]' < file2.txt > "$P.csv"
done < file1.txt

ただし、ここでは、シェル ループを回避して、ファイル内で 1 回のパスのみを実行できます。

awk 'NR == FNR {files[$0]; next}
     FNR == 1 {for (f in files) print > f ".csv"; next}
     {
       for (f in files)
         if ($0 ~ f) print > f ".csv"
     }' file1.txt file2.txt

関連情報