Como imprimir uma coluna para outras colunas caminho combinado sem awk?

1

Eu quero realizar a mesma função que o comando awk :

awk  -F ";" '{print $3 >  "/" $1 "/" $2}' file

Por exemplo:

Eu tenho um arquivo com duas linhas como entrada:

path1;filename_1;f3_1
path2;filename_2;f3_2   

Eu quero a saída como:

  • no arquivo /path1/filename_1 , o conteúdo é f3_1
  • no arquivo /path2/filename_2 , o conteúdo é f3_2

Quando faço isso com o awk, eu tenho o código de saída 141, SIGPIPE. Eu só quero ignorar esse erro.

    
por Mike 09.06.2016 / 10:23

3 respostas

1

Parece que awk está ficando sem identificadores de arquivo. A solução óbvia, se você não puder atualizar para uma versão mais recente do awk , é fechar os arquivos depois de usá-los.

Alguma das combinações path;filename provavelmente aparecerá mais de uma vez?

Se não, tente:

awk  -F ";" '{f="/"$1"/"$2; print $3 > f ; close(f)}' file

Caso contrário, use >> f se a anexação a um arquivo existente estiver correta:

awk  -F ";" '{f="/"$1"/"$2; print $3 >> f ; close(f)}' file

Se o arquivo precisar ser truncado na primeira vez em que for gravado, mas acrescentado a partir de então, será um pouco mais complicado:

awk  -F ";" '{ f="/"$1"/"$2;
               if ( !fnames[f]++ ) { print > f };
               print $3 >> f;
               close(f)
             }' file

A matriz associativa fnames é usada para determinar se o script viu esse nome de arquivo ainda ou não. se não, trunca o arquivo.

    
por 10.06.2016 / 00:42
1

Fazer isso em qualquer coisa, exceto awk , seria bobagem, já que é uma combinação perfeita para as habilidades de awk . Você poderia fazer algo como ( bash-4.3 syntax):

(unset fds; typeset -A fds
while IFS=';' read -r a b c rest; do
  file=/$a/$b
  [[ ${fds[$file]} ]] || exec {fds[$file]}> "$file"
  printf '%s\n' "$c" >&"${fds[$file]}"
done < file)

Mas isso seria muito menos eficiente (veja também Por que usar um loop de shell para processar texto considerado uma prática ruim? ), e ao contrário de alguns awk de implementações que podem contornar isso, faria com que você corresse no limite de número de arquivos abertos simultaneamente se houver muitos arquivos.

Como alternativa, você poderia fazer (POSIX sh syntax):

while IFS=';' read -r a b c rest; do
  printf '%s\n' "$c" >> "/$a/$b"
done < file

Mas isso anexaria o texto aos arquivos em vez de sobrescrevê-los (e ainda assim seria muito menos eficiente do que usar awk ).

Você também pode fazer isso em perl , mas, novamente, você precisa fazer o trabalho de awk de abrir arquivos e manter a lista de fds manualmente:

perl -F ';' -lane '
  $file = "/$F[0]/$F[1]";
  unless (defined $fds{$file}) {
    open $fds{$file}, ">", $file or die "$file: $!\n";
  }
  print {$fds{$file}} $F[2]' < file

(com o mesmo problema em potencial com o limite de arquivos simultaneamente abertos).

    
por 09.06.2016 / 11:00
0

usando o corte:

while read -r line  ; do printf "in the file /%s/%s the content is %s\n" $(echo $line | cut -d';' -f1) $(echo $line | cut -d';' -f2) $(echo $line | cut -d';' -f3) ; done < file

E uma versão muito mais curta (algumas coisas roubadas da resposta de Stéphane Chazelas) e redirecionando a saída para outro arquivo para salvar os resultados:

while IFS=';' read -r f1 f2 f3  ; do printf "in the file /%s/%s the content is %s\n" $f1 $f2 $f3 ; done < files > file2
    
por 09.06.2016 / 10:53