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傳遞給 的程式碼中 shell 變數的內容awk,這是不好的做法,基本上相當於命令注入漏洞(例如,對於$plike的值^/{system("reboot");/)。最好的方法是將 shell 變數原樣傳遞給 awk 並使用 awk 的~運算子進行正規表示式匹配。最好的方法是透過環境變數 和awkENVIRON特殊陣列:

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

但在這裡,您可以避免 shell 循環,只在檔案中執行一次:

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

相關內容