Remova o while
do loop e faça uso da expansão da chave de concha e também FNR
, uma variável awk
incorporada:
awk 'FNR==2{print $0 > "output.dat"}' file{1..80}.dat
Eu pesquisei as perguntas feitas anteriormente e não consigo encontrar uma resposta para o que estou tentando fazer. note, eu sou novo no linux.
Eu tenho vários arquivos como: (na verdade eu tenho 80)
file1.dat
2 5
6 9
7 1
file2.dat
3 7
8 4
1 3
Eu quero acabar com um arquivo contendo todas as segundas linhas. ou seja,
output.dat
6 9
8 4
O que eu tenho até agora faz um loop 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 de shell é 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
muito obrigado por qualquer ajuda com isso
sed
seria suficiente:
sed -sn 2p file{1..80}.dat > output.dat
A opção -s
é necessária para imprimir a segunda linha de cada arquivo, caso contrário, somente a segunda linha do primeiro arquivo será impressa.
Que tal ...
head -n 2 input.dat | tail -n 1 | awk
...
A solução sed
da aragaer é a mais legal, sim. Mas como gosto de um pouco de head|tail
de corte, tenho uma solução head|tail
que suporta vários arquivos, não apenas um único input.dat
. Usando um loop for, em vez de passar uma lista de arquivos para sed, também torna mais fácil fazer outra coisa com o arquivo antes / depois de extrair a segunda linha com 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 multi-linha copiosamente comentada:
NB: o código abaixo será executado. Temos a liberdade de colocar um quebra de linha após um |
, &&
ou ||
e continuar nosso comando na próxima linha; Podemos até colocar comentários no meio. Passei anos sem saber (e não vendo em nenhum lugar). 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
Existem, obviamente, muitas maneiras de fazer isso - acho que eu gosto @saga do aragaer responde melhor .
Aqui está um que usa recursos puramente básicos 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
Para uso eficiente de awk
e sed
em respostas aqui em vários arquivos, é melhor usar a instrução nextfile
para ignorar o processamento de linhas indesejadas em awk
.
awk 'FNR==2{ print >"output.dat"; nextfile}' infile{1..80}.dat
e com sed
, podemos sair quando processamos na linha 3 rd e sed
processará o próximo arquivo.
sed -sn '2p;3q' infile{1..80}.dat > output.dat