awk uma variável como um regex

awk uma variável como um regex

A pergunta é muito simples, li todas as perguntas e ainda não consegui responder! Eu tenho um arquivo simples como este

$cat file1.txt
ALA
AJD
KSF

E quero que o awk use cada um dos valores como regex para imprimir linhas de outro arquivo para outro:

$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

Então meu roteiro é

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

E a saída desejada seria:

$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

Infelizmente, só consigo imprimir os cabeçalhos em cada arquivo. Coloquei manualmente cada valor de file1.txt substituindo $p e funciona perfeitamente. Então acho que o problema é que a variável $p não está sendo bem interpretada. Tentei com aspas, duplo simples. Tentei também muitas sugestões diferentes que encontrei, mas nada parece funcionar!

Responder1

Embora você possa fazer:

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

Isso é ter a cascaexpandiro conteúdo da $pvariável shell no código passado para awk, isso é uma má prática e basicamente equivale a uma vulnerabilidade de injeção de comando (por exemplo, para um valor $plike ^/{system("reboot");/). O melhor é passar a variável shell como está para awk e usar ~o operador do awk para correspondência de regexp. A melhor maneira é através de uma variável de ambiente e um array especial awkde ENVIRON:

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

Mas aqui, você pode evitar o loop do shell e fazer apenas uma passagem nos arquivos:

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

informação relacionada