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
em vez de --lines=-5
para economizar na digitação, se 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)
Este é um verdadeiro uso inútil de gato ; em vez de cat $f | wc -l
, use 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 %código%. Isso garantirá 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 é, portanto, mais portátil . mais portável . Somente no bash (portanto, não use isso se você precisar portar o script para um shell diferente), a maneira melhor 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 se fazer se você quiser que a saída seja exibida na linha de comando, bem como colocá-la em seu arquivo de saída. Caso contrário, use apenas "$f"
para redirecionar o stdout para um arquivo.