Eu quero extrair uma string de texto de muitos arquivos, como posso executar um loop para isso?

3

Eu tenho mil arquivos .xyz , todos os dados numéricos e no mesmo diretório. Alguns deles têm a string de texto "END" no final deles. Não tenho certeza de como fazer o loop de um comando grep para que ele remova o "END" e crie um novo arquivo, enquanto acrescento algo ao final do nome do arquivo original.

Exemplo das últimas linhas de alguns dos meus arquivos

-1.10949170 55.68890280 -67.60000000
-0.92807500 55.64095280 -89.80000000
-0.95770560 55.66495830 -82.40000000
-0.90995000 55.63676110 -94.00000000
-1.03738890 55.65107220 -70.20000000
END

Eu quero isto (removendo o END) de muitos arquivos

-1.10949170 55.68890280 -67.60000000
-0.92807500 55.64095280 -89.80000000
-0.95770560 55.66495830 -82.40000000
-0.90995000 55.63676110 -94.00000000
-1.03738890 55.65107220 -70.20000000

Nome do arquivo original: survey_2015_xxx.xyz
Novo nome de arquivo: survey_2015_xxx_s.xyz

    
por lbeazy 25.02.2016 / 22:41

3 respostas

3

Se o seu head suportar desvios negativos:

for file in *.xyz; do
  if [ "$(tail -n 1 < "$file")" = END ]; then
    head -n -1 < "$file" > "${file%.xyz}_s.xyz"
  fi
done

(se isso não acontecer, substitua head -n -1 por sed '$d' ).

Você pode torná-lo mais eficiente com ksh93 :

for file in *.xyz; do
  if IFS= read -r last4 < "$file" <#((EOF-4)) <#((here=CUR)) &&
    [ "$last4" = END ]; then
    command /opt/ast/bin/head -c "$here" < "$file" > "${file/%.xyz/_s
for file in *.xyz; do
  if IFS= read -r last4 < "$file" <#((EOF-4)) &&
    [ "$last4" = END ]; then
    newfile=${file/%.xyz/_s
for file in *.xyz; do
  if [ "$(tail -n 1 < "$file")" = END ]; then
    head -n -1 < "$file" > "${file%.xyz}_s.xyz"
  fi
done
} cp --reflink=auto -- "$file" "$newfile" && : 1<>; "$newfile" >#((EOF-4)) fi done
}" fi done

Como está apenas usando comandos incorporados.

Se o seu sistema de arquivos oferecer suporte a cópias de retrovisor (que copia arquivos em que os dados não são duplicados até serem modificados, o que economizaria tempo e espaço em disco), você ainda pode usar ksh93 e GNU cp :

for file in *.xyz; do
  if IFS= read -r last4 < "$file" <#((EOF-4)) <#((here=CUR)) &&
    [ "$last4" = END ]; then
    command /opt/ast/bin/head -c "$here" < "$file" > "${file/%.xyz/_s
for file in *.xyz; do
  if IFS= read -r last4 < "$file" <#((EOF-4)) &&
    [ "$last4" = END ]; then
    newfile=${file/%.xyz/_s%pre%}
    cp --reflink=auto -- "$file" "$newfile" &&
      : 1<>; "$newfile" >#((EOF-4))
  fi
done
}" fi done

Ou seja, estamos fazendo uma cópia de reflink e truncando-a em 4 bytes do final.

    
por 25.02.2016 / 22:54
1

Uma alternativa ed , porque você só vive uma vez:

for f in *.xyz; do
    printf '%s\n' ';g/END/d\' "w ${f%.xyz}_s.xyz" q | ed -s "$f"
done

Advertências de nome de arquivo:

  • Nomes de arquivo não podem começar com ! , caso contrário, ed tentará enviar o buffer para um comando.
  • Como ed usa caracteres em branco para delimitar o comando w de seu argumento de nome de caminho, os espaços em branco iniciais nos nomes dos arquivos não serão preservados.
  • Nomes de arquivos com novas linhas causam problemas, pois ed usa novas linhas para delimitar comandos.

Em um mundo são, nenhuma dessas limitações é relevante. Infelizmente ...

    
por 26.02.2016 / 06:38
0

Apenas outra solução usando sed

for file in *.xyz
do
    if [ "$(sed -e '$!d' $file)" = END ]
    then
        sed -e '$d' $file > $file_s.xyz
    fi
done
    
por 25.02.2016 / 23:13