Se você tiver acesso a vim , poderá usar:
for file in ./*
do
if [ -f "${file}" ]
then
vim -c '$d' -c "wq" "${file}"
fi
done
Eu tenho muitos arquivos de texto em um diretório e desejo remover a última linha de todos os arquivos no diretório.
Como posso fazer isso?
Você pode usar esse bom oneliner se tiver o GNU sed .
sed -i '$ d' ./*
Ele removerá a última linha de cada arquivo não oculto no diretório atual. Mude -i para GNU sed significa operar no local e '$ d' comanda o sed para excluir a última linha ( $ significa última e d significa exclusão).
As outras respostas têm problemas se o diretório contiver algo diferente de um arquivo normal ou um arquivo com espaços / novas linhas no nome do arquivo. Aqui está algo que funciona independentemente:
find "$dir" -type f -exec sed -i '$d' '{}' '+'
find "$dir" -type f : encontre os arquivos no diretório $dir
-type f que são arquivos regulares; -exec executa o comando em cada arquivo encontrado sed -i : edite os arquivos no lugar; '$d' : delete ( d ) a última linha ( $ ). '+' : diz ao find para continuar adicionando argumentos para sed (um pouco mais eficiente do que executar o comando para cada arquivo separadamente, graças a @zwol). Se você não quiser descer em subdiretórios, poderá adicionar o argumento -maxdepth 1 a find .
Usando o GNU sed -i '$d' significa ler o arquivo completo e fazer uma cópia dele sem a última linha, enquanto seria muito mais eficiente apenas truncar o arquivo no lugar (pelo menos para arquivos grandes).
Com o% GNUtruncate, você pode fazer:
for file in ./*; do
[ -f "$file" ] &&
length=$(tail -n 1 "$file" | wc -c) &&
[ "$length" -gt 0 ] &&
truncate -s "-$length" "$file"
done
Se os arquivos forem relativamente pequenos, provavelmente seriam menos eficientes, já que executam vários comandos por arquivo.
Observe que, para arquivos que contêm bytes extras após o último caractere de nova linha (após a última linha) ou em outras palavras, se eles tiverem uma linha não delimitada, dependendo do tail implementação, tail -n 1 retornará apenas os bytes extras (como GNU tail ), ou a última linha (devidamente delimitada) e os bytes extras.
Uma abordagem mais portátil:
for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done
Eu não acho que isso precise de qualquer explicação ... exceto talvez que, nesse caso, d seja o mesmo que $d , já que ed , por padrão, seleciona a última linha.
Isso não pesquisará recursivamente e não processará arquivos ocultos (também conhecidos como dotfiles).
Se você quiser editá-los, consulte Como combinar * com arquivos ocultos dentro de um diretório
One-liner compatível com POSIX para todos os arquivos começando recursivamente no diretório atual, incluindo arquivos de pontos:
find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
Apenas para .txt , não recursivamente:
find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
Veja também:
Tags files text-processing