pt delete todos além da primeira e última linha de muitos arquivos

1

Gostaria de processar muitos arquivos * .txt em um diretório - eles têm uma estrutura comum (; separados, cabeçalhos comuns) mas variam no número de linhas que cada um é composto, ou seja, alguns são apenas uma única linha, outras com até 8 linhas de comprimento ..

Gostaria de excluir qualquer linha que não seja a primeira e a última linha de cada arquivo. Alguma ponteira útil?

Atualização: incluí alguns arquivos de dados de teste conforme solicitado:

stat87.txt

Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;                                                                                                             
 87;     ; 46.1123;  8.5440;19010101;19661229;Dres

stat01.txt

Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;                                                                                                             
 1;     ; 47.8400;  8.8500;18910101;19580228;Aach                                                                                                                                                   
 1;  478; 47.8413;  8.8493;19580301;19860630;Aach

e stat56.txt por exemplo.

Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;                                                                                                             
 56;     ; 46.4580;  7.6320;18980101;19450321;Hamb
 56;     ; 46.4580;  7.6320;19450321;19880511;Hamb                                                                                                                                                   
 56;  103; 46.4411;  7.6345;19880601;19990630;Hamb

Neste caso, eu gostaria especialmente de manter a primeira linha das colunas 5 e a última da coluna 6, para que o intervalo de tempo da estação seja capturado.

Resultados:

find . -type f -name \*.txt -printf "%f
19010101;19661229

18910101
19860630

18980101
19990630
" | xargs -0 -I xxxx sed -ni ' 2 { $ { s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\);\([^;]*\).*$/;/ p q } s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$// p } $ { s/^[^;]*;[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$// p }' xxxx

gera ....

'for file in *.txt; do
  sed 'N;s/\n/;/' "$file" > "cleaned$file"
 done'

19010101;19661229

18910101;19860630

18980101;19990630

Eu, então, uso um simples loop sed para limpar os arquivos finais, adicionando o;

Stations_id; Stationshoehe; Geogr.Breite; Geogr.Laenge; von_datum; bis_datum; Stationsname;                                                                                                             
 87;     ; 46.1123;  8.5440;19010101;19661229;Dres
    
por danny_C_O_T_W 30.03.2016 / 23:45

3 respostas

2

Perfeito, abaixo da versão somente do awk:

find . -type f -name \*.txt -printf "%f
$ cat stat01.txt
18910101;19860630
$ cat stat56.txt
18980101;19990630
$ cat stat87.txt
19010101;19661229
" | xargs -0 -I xxxx sed -ni ' 2 { $ { s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\);\([^;]*\).*$/;/ p q } s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$// h } $ { s/^[^;]*;[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$// H x s/\n/;/ p }' xxxx

Obrigado ao muito famoso Sed - Uma Introdução e Tutorial de Bruce Barnett

Resultados:

$ find . -type f -name \*.txt -printf "%f
$ cat test01.txt
Name;Price;Amount;Description
Bread;2.1;3;healthy one
$ cat test02.txt
Name;Price;Amount;Description
Water;0.0;100;For life
Wine;10.3;1;Less than half a glass a day
$ cat test03.txt
Name;Price;Amount;Description
House;1000.0;1;home
Car;500.5;0;no need
Bike;10.3;5;Good for the planet and for me
" | xargs -0 -I xxxx sed -ni ' 2 { $ { s/^[^;]*;\([^;]*\);\([^;]*\).*$/;/ p q } s/^[^;]*;\([^;]*\).*$// p } $ { s/^[^;]*;[^;]*;\([^;]*\).*$// p }' xxxx

----

primeira versão para referência

Com base em sua entrada, eu inventei o formato de arquivo de dados e um script sed para trabalhá-los.

Experimente:

$ cat test01.txt
2.1;3
$ cat test02.txt
0.0
1
$ cat test03.txt
1000.0
5

Remove a primeira linha que contém os cabeçalhos.

Mantém apenas a coluna 2 da primeira linha de dados encontrada e a coluna 3 da última linha de dados do arquivo.

Se um arquivo contiver apenas uma linha de dados, ele permanecerá em uma coluna de linha 2 e coluna 3.

hehehe isso é estranho, mas eu me diverti muito !!!

Os arquivos de dados no diretório atual:

find . -type f -name \*.txt -printf "%f
$ cat stat01.txt
18910101;19860630
$ cat stat56.txt
18980101;19990630
$ cat stat87.txt
19010101;19661229
" | xargs -0 -I xxxx sed -ni ' 2 { $ { s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\);\([^;]*\).*$/;/ p q } s/^[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$// h } $ { s/^[^;]*;[^;]*;[^;]*;[^;]*;[^;]*;\([^;]*\).*$// H x s/\n/;/ p }' xxxx

Resultados:

$ find . -type f -name \*.txt -printf "%f
$ cat test01.txt
Name;Price;Amount;Description
Bread;2.1;3;healthy one
$ cat test02.txt
Name;Price;Amount;Description
Water;0.0;100;For life
Wine;10.3;1;Less than half a glass a day
$ cat test03.txt
Name;Price;Amount;Description
House;1000.0;1;home
Car;500.5;0;no need
Bike;10.3;5;Good for the planet and for me
" | xargs -0 -I xxxx sed -ni ' 2 { $ { s/^[^;]*;\([^;]*\);\([^;]*\).*$/;/ p q } s/^[^;]*;\([^;]*\).*$// p } $ { s/^[^;]*;[^;]*;\([^;]*\).*$// p }' xxxx

Por favor, forneça 2 arquivos de dados curtos e o resultado esperado, e eu modificarei esta resposta.

    
por 31.03.2016 / 01:31
0

Você precisará de um loop sobre os arquivos para isso:

for file in *.txt; do
  lines=$(wc -l < "$file")
  if [ "$lines" -lt 3 ]; then
    echo "$file is short enough, not touching it."
  else
    # for testing, you can also use the -i option
    sed -n '1p;$p' "$file" > "$file.new"
  fi
done

O loop é necessário se você tiver arquivos com apenas uma linha de comprimento. Com o comando fornecido pelo thrig eles serão exibidos duas vezes (tente echo 1|sed -n '1p;$p' ).

    
por 31.03.2016 / 01:12
0

O Gawk é uma ferramenta muito melhor para essa tarefa do que o sed. Reaproveitando o pipeline find-xargs da abordagem original e usando a mesma nomenclatura de saída:

find . -type f -name \*.txt -printf "%f
find . -type f -name \*.txt -printf "%f%pre%" | xargs -0 gawk -F\; '
    FNR==2  { von = $5 }
    ENDFILE { print von FS $6 > "cleaned" FILENAME }
'
" | xargs -0 gawk -F\; ' FNR==2 { von = $5 } ENDFILE { print von FS $6 > "cleaned" FILENAME } '

O código é muito mais simples, mais claro e eminentemente mais sustentável.

    
por 31.03.2016 / 23:14