Awk - envia a segunda linha de vários arquivos .dat para um arquivo

9

Eu tenho vários arquivos, algo como: (na realidade eu tenho 80)

file1.dat

2 5

6 9

7 1

file2.dat

3 7

8 4

1 3

Quero terminar com um arquivo contendo todas as segundas linhas. ie

output.dat

6 9

8 4

O que eu tenho até agora dá laços nos nomes dos arquivos, mas depois sobrescreve o arquivo antes dele. por exemplo, a saída dos arquivos acima seria apenas

8 4

meu script shell fica assim:

post.sh

TEND = 80

TINDX = 0

while [ $TINDX - lt $TEND]; do

awk '{ print NR==2 "input-$TINDX.dat > output.dat

TINDX = $((TINDX+1))

done
Rowland
fonte

Respostas:

17

Remova o whileloop e faça uso da expansão de chaves e também de FNRuma awkvariável interna:

awk 'FNR==2{print $0 > "output.dat"}' file{1..80}.dat
jimmij
fonte
9
ainda mais curtoawk 'FNR==2' file{1..80}.dat > output.dat
Archemar 13/01/2015
7

Que tal ... head -n 2 input.dat | tail -n 1 | awk...

HarveyP
fonte
Sim, head/ tailé definitivamente uma opção, você não precisa de awkentão.
jimmij
7

sed seria suficiente:

sed -sn 2p file{1..80}.dat > output.dat

-s A opção é necessária para imprimir a segunda linha de cada arquivo; caso contrário, apenas a segunda linha do primeiro arquivo será impressa.

aragaer
fonte
2

a sedsolução do aragaer é melhor, sim. Mas como eu gosto de head|tailcortar, tenho uma head|tailsolução que suporta vários arquivos, não apenas um input.dat. O uso de um loop for, em vez de passar uma lista de arquivos para o sed, também facilita a realização de outras coisas com o arquivo antes / depois de extrair a segunda linha com o sed.

# empty output.dat first
rm output.dat

# have a one-liner
for file in *.dat; do head -2 $file | tail -1 >> output.dat; done 

Versão multilíngue copiosamente comentada:

Nota: o código abaixo será executado. Somos livres para colocar uma quebra de linha depois de um |, &&ou ||, e continuar o nosso comando na linha seguinte; podemos até colocar comentários no meio. Passei anos sem saber disso (e realmente não vendo isso em lugar nenhum). Esse estilo é menos útil no prompt interativo, mas limpa os arquivos de script sem fim.

# empty output.dat first
rm output.dat

for file in *.dat; do
    # file -> lines 1 and 2 of file
    head -2 $file |
    # lines 1 and 2 of file -> line 2 of file >> appended to output.dat
    tail -1 >> output.dat
done
Esteis
fonte
0

Obviamente, existem muitas maneiras de fazer isso - acho que gosto mais da resposta sed do @ aragaer .

Aqui está um que usa built-in puramente bash e não precisa usar nenhum utilitário externo:

for f in file{1..80}.dat; do
    { read && read && printf "%s\n" "$REPLY"; } < "$f"
done > output.dat
Trauma Digital
fonte
0

Para um uso eficiente awke sednas respostas aqui em vários arquivos, é melhor usar a nextfileinstrução para pular o processamento de linhas indesejadas awk.

awk 'FNR==2{ print >"output.dat"; nextfile}' infile{1..80}.dat

e com sed, podemos sair ao processar na linha e sedprocessaremos o próximo arquivo.

sed -sn '2p;3q' infile{1..80}.dat > output.dat
αғsнιη
fonte