Eu tenho um arquivo foo.txt
, contendo as seguintes linhas:
a
b
c
Eu quero um comando simples que resulte no conteúdo de foo.txt
ser:
a
b
Eu tenho um arquivo foo.txt
, contendo as seguintes linhas:
a
b
c
Eu quero um comando simples que resulte no conteúdo de foo.txt
ser:
a
b
Respostas:
Usando GNU sed
:
sed -i '$ d' foo.txt
A -i
opção não existe em GNU sed
versões anteriores à 3.95, portanto, você deve usá-la como um filtro com um arquivo temporário:
cp foo.txt foo.txt.tmp
sed '$ d' foo.txt.tmp > foo.txt
rm -f foo.txt.tmp
Claro, nesse caso, você também pode usar em head -n -1
vez de sed
.
Mac OS:
No Mac OS X (a partir de 10.7.4), o equivalente ao sed -i
comando acima é
sed -i '' -e '$ d' foo.txt
$ d
uma regex. É um comando sed. d
é o comando para excluir uma linha, enquanto $
significa "a última linha no arquivo". Ao especificar um local (chamado "range" no sed lingo) antes de um comando, esse comando é aplicado apenas ao local especificado. Portanto, este comando diz explicitamente "no intervalo da última linha de um arquivo, exclua-o". Muito liso e direto ao ponto, se você me perguntar.
Essa é de longe a solução mais rápida e simples, especialmente em arquivos grandes:
head -n -1 foo.txt > temp.txt ; mv temp.txt foo.txt
se você deseja excluir a linha superior, use o seguinte:
tail -n +2 foo.txt
o que significa linhas de saída começando na linha 2.
Não use sed
para excluir linhas da parte superior ou inferior de um arquivo - é muito muito lento se o arquivo for grande.
head -n -1 foo.txt
é suficiente
brew install coreutils
(utilitários principais do GNU) e usar em ghead
vez de head
.
FILE=$1; TAIL=$2; head -n -${TAIL} ${FILE} > temp ; mv temp ${FILE}
Execute-o para excluir 4 linhas, por exemplo, do myfile como: é ./TAILfixer myfile 4
claro que primeiro o torna executávelchmod +x TAILfixer
sed
, esse comando também é muito lento
Eu tive problemas com todas as respostas aqui porque estava trabalhando com um arquivo ENORME (~ 300 GB) e nenhuma das soluções foi dimensionada. Aqui está a minha solução:
dd if=/dev/null of=<filename> bs=1 seek=$(echo $(stat --format=%s <filename> ) - $( tail -n1 <filename> | wc -c) | bc )
Em palavras: Descubra o tamanho do arquivo que você quer acabar com (comprimento de arquivo menos o comprimento da duração da sua última linha, usando bc
) e, conjunto que posição para ser o fim do arquivo (por dd
ing um byte de /dev/null
em isto).
Isso é rápido porque tail
começa a ler a partir do final e dd
substitui o arquivo no lugar em vez de copiar (e analisar) todas as linhas do arquivo, que é o que as outras soluções fazem.
NOTA: Isso remove a linha do arquivo no lugar! Faça um backup ou teste em um arquivo fictício antes de testá-lo em seu próprio arquivo!
Para remover a última linha de um arquivo sem ler o arquivo inteiro ou reescrever nada , você pode usar
tail -n 1 "$file" | wc -c | xargs -I {} truncate "$file" -s -{}
Para remover a última linha e também imprimi-la no stdout ("pop" it), você pode combinar esse comando com tee
:
tail -n 1 "$file" | tee >(wc -c | xargs -I {} truncate "$file" -s -{})
Esses comandos podem processar eficientemente um arquivo muito grande. É semelhante e inspirado pela resposta de Yossi, mas evita o uso de algumas funções extras.
Se você vai usá-las repetidamente e desejar manipulação de erros e outros recursos, use o poptail
comando aqui:
https://github.com/donm/evenmoreutils
truncate
não está disponível no OS X por padrão. Mas é fácil de instalar usando Brew: brew install truncate
.
Usuários de Mac
Se você deseja excluir apenas a última linha sem alterar o arquivo, faça
sed -e '$ d' foo.txt
Se você deseja excluir a última linha do arquivo de entrada, faça
sed -i '' -e '$ d' foo.txt
-i ''
diz ao sed para modificar o arquivo no local, mantendo um backup em um arquivo com a extensão fornecida como parâmetro. Como o parâmetro é uma sequência vazia, nenhum arquivo de backup é criado. -e
diz ao sed para executar um comando. O comando $ d
significa: encontre a última linha ( $
) e exclua-a ( d
).
No Mac, a cabeça -n -1 não funcionará. E, eu estava tentando encontrar uma solução simples [sem se preocupar com o tempo de processamento] para resolver esse problema usando apenas os comandos "head" e / ou "tail".
Tentei a seguinte sequência de comandos e fiquei feliz por poder resolvê-la usando o comando "tail" [com as opções disponíveis no Mac]. Portanto, se você estiver no Mac e quiser usar apenas "cauda" para resolver esse problema, poderá usar este comando:
arquivo cat.txt | cauda -r | cauda -n +2 | cauda -r
1> tail -r: simplesmente inverte a ordem das linhas em sua entrada
2> tail -n +2: imprime todas as linhas a partir da segunda linha em sua entrada
ghead -n -1
echo -e '$d\nw\nq'| ed foo.txt
sed '$d'
.
awk 'NR>1{print buf}{buf = $0}'
Essencialmente, este código diz o seguinte:
Para cada linha após a primeira, imprima a linha em buffer
para cada linha, redefina o buffer
O buffer está atrasado em uma linha, portanto, você acaba imprimindo as linhas 1 a n-1
awk "NR != `wc -l < text.file`" text.file |> text.file
Este trecho faz o truque.
Ambas as soluções estão aqui de outras formas. Achei isso um pouco mais prático, claro e útil:
Usando dd:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
dd if=${ORIGINALFILE} of=${ORIGINALFILE}.tmp status=none bs=1 count=$(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc )
/bin/mv -f ${ORIGINALFILE}.tmp ${ORIGINALFILE}
Usando truncado:
BADLINESCOUNT=1
ORIGINALFILE=/tmp/whatever
truncate -s $(printf "$(stat --format=%s ${ORIGINALFILE}) - $(tail -n${BADLINESCOUNT} ${ORIGINALFILE} | wc -c)\n" | bc ) ${ORIGINALFILE}
sed '$d' ~/path/to/your/file/name
sed -i '' -e '$ d' ~/path/to/your/file/name
Veja como você pode fazer isso manualmente (eu pessoalmente uso muito esse método quando preciso remover rapidamente a última linha de um arquivo):
vim + [FILE]
Este +
sinal indica que, quando o arquivo é aberto no editor de texto vim, o cursor será posicionado na última linha do arquivo.
Agora basta pressionar d
duas vezes no teclado. Isso fará exatamente o que você deseja - remova a última linha. Depois disso, pressione :
seguido de x
e, em seguida, pressione Enter
. Isso salvará as alterações e o levará de volta ao shell. Agora, a última linha foi removida com sucesso.
sed -i
comando acima ésed -i '' -e '$ d' foo.txt
. Além disso,head -n -1
atualmente não funcionará em um Mac.