Grep / awk em vários arquivos para saída única

0

Eu tenho vários arquivos txt contendo dados, onde eu uso grep para procurar por uma string atual de texto, e uso awk para filtrar a variável que eu preciso. A string é repetida através do arquivo, então eu atualmente uso este comando para extrair a string desejada:

grep 'text' *.txt | awk ' NR==1  {print $2 } ' > outputfile

O problema é que eu quero percorrer vários arquivos na pasta e, para cada arquivo, obter a variável extraída gravada em um único arquivo de saída. Sei que a pergunta já foi respondida antes, mas estou bem atualizada e tenho algumas dificuldades para implementar.

Qualquer comentário seria muito apreciado!

    
por Knut 25.01.2016 / 08:29

2 respostas

1

Eu faria uma iteração nos arquivos no bash, mantendo o nome de cada um deles, para que você pudesse redirecionar a saída para diferentes arquivos de saída para cada iteração.

Por exemplo, assim (não testado):

PREFIX="/tmp/outputs"   # define where to store all the outputs
mkdir -p "${PREFIX}"    # make sure the outputs dir exists

for FILE in *.txt       # get the file names you want to work on
do
  # use ${PREFIX}/${FILE} to redirect output to a 
  # file that's associated with the input
  grep 'text' "${FILE}" | awk ' NR==1 {print $2 } ' > "${PREFIX}/${FILE}"
done
    
por 25.01.2016 / 08:38
1

Se bem entendi, você deseja fazer o seguinte para cada arquivo .txt :

  • Localize a primeira linha que contém o padrão text .
  • Nessa linha, pegue o segundo campo separado por espaço em branco e grave-o em um arquivo cujo nome esteja relacionado ao arquivo de entrada.

Você não está dizendo como o nome do arquivo de saída deve ser construído. Vou fazer o mesmo que o arquivo de entrada, mas terminando em .out em vez de .txt .

Você pode fazer isso com um loop de shell.

for x in *.txt; do
  grep 'text' -- "$x" | awk '{print $2; exit}' >"${x%.*}.out"
done

Sair do awk assim que estiver pronto, seu trabalho é um pouco mais rápido do que dizer para continuar lendo, mas não fazer nada. Outra possibilidade é ignorar completamente o awk e fazer com que o shell faça a divisão de linha (se isso é mais rápido ou mais lento, depende de muitos fatores que não vou arriscar em previsões):

for x in *.txt; do
  grep 'text' -- "$x" | read -r first second rest && printf '%s\n' "$rest" >"${x%.*}.out"
done

Uma abordagem diferente seria fazer todo o trabalho no awk. O awk pode atuar em vários arquivos e você pode usar o redirecionamento do awk para a saída. Isso requer forking menos processos. É bem direto em Gawk (GNU awk):

awk '/text/ {print $2 >substr(FILENAME, 1, length(FILENAME)-4) ".out"; nextfile}' *.txt

Em uma implementação do awk que não possui nextfile , você precisa manipular manualmente as transições para o próximo arquivo, o que torna essa abordagem menos atraente (mais complexa e menos eficiente).

awk '
    FNR==1 {first=1}
   first && /text/ {print $2 >substr(FILENAME, 1, length(FILENAME)-4) ".out"; first=0}' *.txt
    
por 26.01.2016 / 00:33