Como posso imprimir a segunda à última linha de muitos arquivos em um único arquivo? [duplicado]

1

Eu tenho muitos arquivos CSV em um diretório que tem vários comprimentos. Eu gostaria de colocar o segundo a última linha de cada arquivo em um arquivo. Eu tentei algo como tail -2 * | head -1 > file.txt , então percebi porque isso não funciona.

Estou usando o BusyBox v1.19.4.

Edit: Eu vejo a semelhança com algumas outras perguntas, mas isso é diferente porque é sobre a leitura de vários arquivos. O loop for na resposta de Tom Hunt é o que eu precisava e não tinha pensado antes.

    
por aswine 19.10.2015 / 23:22

2 respostas

7
for i in *; do tail -2 "$i" | head -1; done >>file.txt

Isso deve ser sh (e, portanto, o Busybox) compatível, mas eu não tenho um não-bash disponível para testar ATM.

Editado de acordo com comentários úteis.

    
por 19.10.2015 / 23:32
4

Com um GNU ou BSD sed :

sed -s 'x;$!d' -- files... >outfile

... por exemplo:

for   i in        10 50 100 1000
do    seq "$i"   >file"$i"
done
sed -s 'x;$!d' -- file[15]0*
9
99
999
49

Você também pode fazer isso com tail :

tail -n2 file[15]0* | sed -ne'n;p;n;n'
9
99
999
49

... mas você precisa ter certeza de que há pelo menos duas linhas em cada arquivo, porque nesse caso sed não é -s eparating nenhum fluxo, e um -off afetará o resto da saída. Mas tail definitivamente não vai imprimir nenhum mais que as duas últimas linhas em cada arquivo, e ele seguirá cada conjunto daqueles com uma linha em branco, e liderará cada conjunto com sua especificação ' d nome do arquivo cabeçalho (o que pode causar problemas se houver novas linhas nos nomes de arquivos, na verdade) .

Isso é o que tail imprime:

tail -n2 file[15]0*
==> file10 <==
9
10

==> file100 <==
99
100

==> file1000 <==
999
1000

==> file50 <==
49
50

... o que, se você não tem uma opção melhor, não é tão difícil de controlar.

E pensando nisso, se houver menos de duas linhas em um arquivo, a solução sed emitirá uma linha em branco para esse arquivo. Se você preferir, não escreveu nada para esse arquivo:

sed -s 'x;$!d;1d' -- file[15]0*

... faria o truque.

O comando tail | sed funciona somente com busybox builtins, embora, infelizmente, busybox sed não não manipule a opção -s eparate streams. Pelo menos, minha compilação não:

busybox sed --help
BusyBox v1.21.1 (2013-07-28 11:02:27 EDT) multi-call binary.

Usage: sed [-inr] [-f FILE]... [-e CMD]... [FILE]...
or: sed [-inr] CMD [FILE]...

Além disso, é frustrante que toybox sed (o que eu prefiro e que esteja oficialmente incluído nos sistemas android) falsamente reporta que faz apoiar a opção em sua saída --help , e então se recusa a reconhecê-la em outro lugar:

toybox sed -s -e 'x;$!d' -- file[15]0*
usage: sed [-inrE] [-e SCRIPT]...|SCRIPT [-f SCRIPT_FILE]... [FILE...]

Stream editor. Apply one or more editing SCRIPTs to each line of input
(from FILE or stdin) producing output (by default to stdout).

-e  add SCRIPT to list
-f  add contents of SCRIPT_FILE to list
-i  Edit each file in place.
-n  No default output. (Use the p command to output matched lines.)
-r  Use extended regular expression syntax.
-E  Alias for -r.
-s  Treat input files separately (implied by -i)

...

sed: Unknown option s

caramba.

    
por 20.10.2015 / 00:41