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"

殻があるという意味です。拡張$pawkこれは悪い習慣であり、基本的にコマンドインジェクションの脆弱性に対応します(たとえば、$pなどの値の場合^/{system("reboot");/)。最善のアプローチは、シェル変数をそのままawkに渡し、~正規表現の一致にawkの演算子を使用することです。最善の方法は、環境変数と特別な配列を使用することawkですENVIRON

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

ただし、ここではシェルループを避け、ファイル内で一度だけ実行できます。

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

関連情報