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