Script muito simples para remover as últimas 5 linhas de uma série de arquivos de texto

3

Por algum motivo, esse script gera três arquivos para cada original, em vez de um.

Deve ter feito algum erro trivial - eu sou novo nisso!

Muito obrigado se alguém pudesse explicar por que isso acontece.

Roteiro:-

for f in *.txt
do
   noOfRows=$(cat $f | wc -l)
   relevantRows=$(expr $noOfRows - 5)
   head -n $relevantRows $f | tee ${f%.txt}-Amended.txt
done

Resultado do comando ls: -

E12-5_F2_NEG-Amended-Amended-Amended.txt  E12-5_M3_POS-Amended-Amended-Amended.txt
E12-5_F2_NEG-Amended-Amended.txt          E12-5_M3_POS-Amended-Amended.txt
E12-5_F2_NEG-Amended.txt                  E12-5_M3_POS-Amended.txt
E12-5_F2_NEG.txt                          E12-5_M3_POS.txt
E12-5_F2_POS-Amended-Amended-Amended.txt  E12-5_M4_NEG-Amended-Amended-Amended.txt
E12-5_F2_POS-Amended-Amended.txt          E12-5_M4_NEG-Amended-Amended.txt
E12-5_F2_POS-Amended.txt                  E12-5_M4_NEG-Amended.txt
E12-5_F2_POS.txt                          E12-5_M4_NEG.txt
E12-5_F5_NEG-Amended-Amended-Amended.txt  E12-5_M4_POS-Amended-Amended-Amended.txt
E12-5_F5_NEG-Amended-Amended.txt          E12-5_M4_POS-Amended-Amended.txt
E12-5_F5_NEG-Amended.txt                  E12-5_M4_POS-Amended.txt
E12-5_F5_NEG.txt                          E12-5_M4_POS.txt
E12-5_F5_POS-Amended-Amended-Amended.txt  E12-5_M7_NEG-Amended-Amended-Amended.txt
E12-5_F5_POS-Amended-Amended.txt          E12-5_M7_NEG-Amended-Amended.txt
E12-5_F5_POS-Amended.txt                  E12-5_M7_NEG-Amended.txt
E12-5_F5_POS.txt                          E12-5_M7_NEG.txt
E12-5_M3_NEG-Amended-Amended-Amended.txt  E12-5_M7_POS-Amended-Amended-Amended.txt
E12-5_M3_NEG-Amended-Amended.txt          E12-5_M7_POS-Amended-Amended.txt
E12-5_M3_NEG-Amended.txt                  E12-5_M7_POS-Amended.txt
E12-5_M3_NEG.txt                          E12-5_M7_POS.txt

Muito obrigado, Adam

user193170
fonte

Respostas:

5

este script produz três arquivos para cada original ... Muito obrigado se alguém puder explicar por que isso acontece.

Desde a E12-5_F2_NEG-Amended.txt termina em .txt ele será escolhido pelo seu script na próxima vez que você executá-lo.

Os resultados triplos indicam que você executou seu script três vezes ao depurá-lo.

Se a saída do script para $f.new em vez de ${f%.txt}-Amended.txt, você não teria esse problema.

Como alternativa, coloque rm *Amended.txt no início do programa. Se você tiver um número muito grande de arquivos em um diretório, isso pode ser lento em variantes Unix mais antigas.

Outra opção é enviar os arquivos para um subdiretório (então algo como "new/${f%.txt}.Amended.txt" )

RedGrittyBrick
fonte
3

Você pode fazer o que seu script está tentando alcançar em uma única linha:

head --lines=-5 input.txt > output.txt

Em um loop for:

for f in *.txt; do head --lines=-5 "$f" > "${f%.txt}-Amended.txt"; done

Você pode usar -n -5 ao invés de --lines=-5 para economizar em digitação se você quiser.

Como a RedGrittyBrick aponta, o motivo pelo qual você tem três arquivos por entrada provavelmente é porque você executou o script várias vezes e, como as saídas terminam com .txt, elas foram capturadas pelo glob * .txt dos scripts sucessivos.

Agora vou criticar seu script específico.

noOfRows=$(cat $f | wc -l)

Isto é verdadeiramente uso inútil de gato ; ao invés de cat $f | wc -l, usar wc -l "$f". Provavelmente não é tão importante neste roteiro específico, mas é bom não desenvolver maus hábitos. Falando sobre maus hábitos: Sempre cite variáveis , por exemplo. "$f". Isso fará com que o nome do arquivo seja tratado como um único argumento, mesmo que contenha espaço em branco.

relevantRows=$(expr $noOfRows - 5)

Não há nada realmente errado aqui, embora eu geralmente prefira usar algo como

relevantRows=$((noOfRows-5))

AFAIK não há diferença de desempenho entre os dois, mas acho o caminho mais visualmente agradável; e mais importante, a maneira que eu descrevi é definida no POSIX, e é assim mais portátil . Somente no bash (portanto, não use isso se precisar portar o script para um shell diferente), melhor maneira de fazer isso em um script seria usar let:

let noOfRows-=5

... que subtrairia 5 do número contido na variável $ noOfRows, significando que não há necessidade de criar a variável $ relevantRows.

head -n $relevantRows $f | tee ${f%.txt}-Amended.txt

Esta é a coisa correta a fazer E se você quer que a saída seja exibida na linha de comando, bem como colocá-la no arquivo de saída. Caso contrário, basta usar > para redirecionar o stdout para um arquivo.

evilsoup
fonte
1
o $(()) maneira é POSIX, e é realmente o let método que é uma adição de Bash não padrão. expr também é menos definido em função do que o POSIX $(()) construção, então o último deve ser preferido se a portabilidade for necessária (o que geralmente é uma boa diretriz para roteiros bem formados e evitando maus hábitos). Veja por exemplo wiki.bash-hackers.org/commands/builtin/… .
Daniel Andersson
@ Daniel obrigado por essa informação, incorporada na resposta
evilsoup
Excelente crítica, e eu concordo com cada pedacinho dela, mas você omitiu realmente responder a pergunta original (“por que há saída triplicada”). Veja @ RedGrittyBrick responda por isso.
kopischke