Eu tenho alguns arquivos que gostaria de excluir a última nova linha, se for o último caractere de um arquivo. od -c
mostra que o comando que eu executo grava o arquivo com uma nova linha à direita:
0013600 n t > \n
Eu tentei alguns truques com o sed, mas o melhor que pude pensar não está fazendo o truque:
sed -e '$s/\(.*\)\n$/\1/' abc
Alguma idéia de como fazer isso?
\n
, no linux é é um personagemRespostas:
ou, para editar o arquivo no local:
[Nota do editor:
-pi -e
foi originalmente-pie
, mas, como observado por vários comentaristas e explicado por @hvd, o último não funciona.]Isso foi descrito como uma 'blasfêmia perl' no site do awk que eu vi.
Mas, em um teste, funcionou.
fonte
chomp
. E é melhor do que arrastar o arquivo.perl -pi -e 'chomp if eof' filename
, para editar um arquivo no local em vez de criar um arquivo temporárioperl -pie 'chomp if eof' filename
-> Não é possível abrir o script perl "chomp if eof": Esse arquivo ou diretório não existe;perl -pi -e 'chomp if eof' filename
-> funcionaVocê pode tirar vantagem do fato de que as substituições de comandos do shell removem os caracteres de nova linha à direita :
Forma simples que funciona em bash, ksh, zsh:
Alternativa portátil (compatível com POSIX) (um pouco menos eficiente):
Nota:
in.txt
terminar com vários caracteres de nova linha, a substituição do comando removerá todos eles - obrigado, @Sparhawk. (Ele não remove caracteres de espaço em branco que não sejam linhas novas à direita).printf %s
garante que nenhuma nova linha seja anexada à saída (é a alternativa compatível com POSIX para a não-padrãoecho -n
; consulte http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html e https: //unix.stackexchange. com / a / 65819 )Um guia para as outras respostas :
Se o Perl estiver disponível, escolha a resposta aceita - é simples e economiza memória (não lê o arquivo de entrada inteiro de uma vez).
Caso contrário, considere a resposta Awk de ghostdog74 - é obscura, mas também eficiente em termos de memória ; um equivalente mais legível (compatível com POSIX) é:
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
bloco, onde é impressa sem deixar rasto,\n
devido à definição do separador de registros de saída (OFS
) como uma sequência vazia.Se você deseja uma solução detalhada, porém rápida e robusta, que realmente edite no local (em vez de criar um arquivo temporário que substitui o original), considere o script Perl do jrockway .
fonte
Você pode fazer isso com o
head
GNU coreutils, ele suporta argumentos relativos ao final do arquivo. Portanto, para deixar de fora o último byte, use:Para testar uma nova linha final, você pode usar
tail
ewc
. O exemplo a seguir salva o resultado em um arquivo temporário e sobrescreve o original:Você também pode usar
sponge
frommoreutils
para fazer a edição "no local":Você também pode criar uma função reutilizável geral colocando isso em seu
.bashrc
arquivo:Atualizar
Conforme observado por KarlWilbur nos comentários e usado na resposta de Sorentar ,
truncate --size=-1
pode substituirhead -c-1
e oferecer suporte à edição no local.fonte
truncate --size=-1
vez dehead -c -1
redimensionar o arquivo de entrada em vez de ler no arquivo de entrada, gravá-lo em outro arquivo e substituir o original pelo arquivo de saída.head -c -1
removerá o último caractere, independentemente de ser uma nova linha ou não, é por isso que você deve verificar se o último caractere é uma nova linha antes de removê-lo.Edição 2:Aqui está umaawk
versão (corrigida) que não acumula uma matriz potencialmente enorme:awk '{if (linha) linha de impressão; line = $ 0} END {printf $ 0} 'abcfonte
awk
versão. São necessárias duas compensações (e um teste diferente) e usei apenas uma. No entanto, você pode usar emprintf
vez deORS
.head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
gawk
fonte
awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file
isso deve ser mais fácil de ler.awk 'NR>1 {print p} {p=$0} END {printf $0}' file
.printf
é o argumento de formato . Portanto, se o arquivo de entrada tiver algo que possa ser interpretado como um especificador de formato%d
, você receberá um erro. Uma correção seria alterá-lo paraprintf "%s" $0
Um método muito simples para arquivos de linha única, exigindo o eco GNU do coreutils:
fonte
\n
está presente. À medida que é convertido em uma nova linha.$(...)
é citado/bin/echo -n "$(cat infile)"
Além disso, não tenho certeza de qual seria o tamanho máximoecho
ou o shell entre as versões / distros do OS / shell (eu estava apenas pesquisando isso e era uma toca de coelho), então estou não tenho certeza de quão portátil (ou de alto desempenho) seria para algo que não seja arquivos pequenos - mas para arquivos pequenos, ótimo.Se você quiser fazer o que é certo, precisará de algo como isto:
Abrimos o arquivo para leitura e anexação; abrir para anexar significa que já estamos
seek
no final do arquivo. Em seguida, obtemos a posição numérica do final do arquivo comtell
. Usamos esse número para procurar um caractere e depois lemos esse caractere. Se for uma nova linha, truncamos o arquivo para o caractere antes dessa nova linha, caso contrário, não fazemos nada.Isso é executado em tempo constante e espaço constante para qualquer entrada e também não requer mais espaço em disco.
fonte
Aqui está uma solução Python agradável e arrumada. Não tentei ser conciso aqui.
Isso modifica o arquivo no local, em vez de fazer uma cópia do arquivo e remover a nova linha da última linha da cópia. Se o arquivo for grande, será muito mais rápido que a solução Perl que foi escolhida como a melhor resposta.
Ele trunca um arquivo em dois bytes se os últimos dois bytes forem CR / LF ou em um byte se o último byte for LF. Ele não tenta modificar o arquivo se o último byte (s) não for (CR) LF. Ele lida com erros. Testado em Python 2.6.
Coloque isso em um arquivo chamado "striplast" e
chmod +x striplast
.PS No espírito do "Perl golf", aqui está a minha solução Python mais curta. Ele retira o arquivo inteiro da entrada padrão para a memória, retira todas as novas linhas do final e grava o resultado na saída padrão. Não é tão conciso quanto o Perl; você simplesmente não pode vencer o Perl por coisas rápidas e complicadas como essa.
Remova o "\ n" da chamada
.rstrip()
e removerá todo o espaço em branco do final do arquivo, incluindo várias linhas em branco.Coloque isso em "slurp_and_chomp.py" e execute
python slurp_and_chomp.py < inputfile > outputfile
.fonte
Uma solução rápida é usar o utilitário gnu
truncate
:O teste será verdadeiro se o arquivo tiver uma nova linha à direita.
A remoção é muito rápida, realmente implementada, nenhum novo arquivo é necessário e a pesquisa também está lendo no final apenas um byte (
tail -c1
).fonte
[ -z $(tail -c1 filename) ] && truncate -s -1 filename
(também, em resposta a outro comentário, otruncate
comando não funciona com stdin, um nome de arquivo é necessário)Ainda outro perl WTDI:
fonte
Consulte também Corresponder qualquer caractere (incluindo novas linhas) no sed .
fonte
tr -d '\n'
Usando dd:
fonte
fonte
g
ou os parênteses em tornoeof
:perl -pi -e 's/\n$// if eof' your_file
.Assumindo o tipo de arquivo Unix e você deseja apenas a última nova linha que funcione.
Não funcionará em várias novas linhas ...
* Funciona apenas se a última linha for uma linha em branco.
fonte
sed
solução que funciona mesmo para uma última linha não-branco: stackoverflow.com/a/52047796Outra resposta FTR (e a minha favorita!): Faz eco / cat a coisa que você deseja retirar e capturar a saída através de backticks. A nova linha final será removida. Por exemplo:
fonte
POSIX SED:
'$ {/ ^ $ / d}'
fonte
echo -en 'a\nb\n' | sed '${/^$/d}'
não removerá nada.echo -en 'a\nb\n\n' | sed '${/^$/d}'
será removido porque a última linha inteira está em branco.Essa é uma boa solução se você precisar trabalhar com pipes / redirecionamentos em vez de ler / produzir um ou para um arquivo. Isso funciona com uma ou várias linhas. Funciona se existe uma nova linha à direita ou não.
Detalhes:
head -c -1
trunca o último caractere da sequência, independentemente de qual seja o caractere. Portanto, se a sequência não terminar com uma nova linha, você estaria perdendo um caractere.sed '$s/$//'
. O primeiro$
meio aplica apenas o comando à última linha.s/$//
significa substituir o "fim da linha" por "nada", que basicamente não está fazendo nada. Mas tem um efeito colateral de adicionar uma nova linha à direita, se não houver uma.Nota: O padrão do Mac
head
não suporta a-c
opção. Você pode fazerbrew install coreutils
e usar em seughead
lugar.fonte
A única vez que eu queria fazer isso é no código de golfe e, em seguida, copiei meu código do arquivo e colei em uma
echo -n 'content'>file
instrução.fonte
fonte
Eu tive um problema semelhante, mas estava trabalhando com um arquivo do Windows e precisava manter os CRLF - minha solução no linux:
fonte
Deve remover qualquer última ocorrência de \ n no arquivo. Não funciona em arquivos grandes (devido à limitação do buffer sed)
fonte
rubi:
ou:
fonte