awk uma variável como um regex

3

A pergunta é realmente simples, eu li todas as perguntas e ainda não consigo! 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 script é

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 o resultado desejado 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ó recebo os cabeçalhos impressos em cada arquivo. Eu coloquei manualmente cada valor de file1.txt substituindo $ p e funciona perfeitamente. Então eu acho que o problema é que a variável $ p não foi bem interpretada. Eu tentei com aspas, duplamente simples. Eu tentei também muitas sugestões diferentes que encontrei, mas nada parece funcionar!

    
por user197531 28.10.2016 / 12:25

1 resposta

4

Enquanto você poderia fazer:

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

Isso tem o shell expandir o conteúdo da variável $p shell no código passado para awk , isso é uma prática ruim e basicamente equivale a uma vulnerabilidade de injeção de comando (por exemplo, para um valor de $p como ^/{system("reboot");/ ). O melhor é passar a variável do shell como é awk e usar o operador ~ do awk para correspondência de expressões regulares. A melhor maneira é através de uma variável de ambiente e awk ' ENVIRON array especial:

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
    
por 28.10.2016 / 12:40