Tenho arquivos que terminam em uma ou mais novas linhas e devem terminar em apenas uma nova linha. Como posso fazer isso com as ferramentas Bash / Unix / GNU?
Exemplo de arquivo incorreto:
1\n
\n
2\n
\n
\n
3\n
\n
\n
\n
Exemplo de arquivo corrigido:
1\n
\n
2\n
\n
\n
3\n
Em outras palavras: deve haver exatamente uma nova linha entre o EOF e o último caractere não-nova linha do arquivo.
Implementação de referência
Leia o conteúdo do arquivo, corte uma única nova linha até que não haja mais duas novas no final e escreva de volta:
#! /bin/python
import sys
with open(sys.argv[1]) as infile:
lines = infile.read()
while lines.endswith("\n\n"):
lines = lines[:-1]
with open(sys.argv[2], 'w') as outfile:
for line in lines:
outfile.write(line)
Esclarecimento: É claro que a tubulação é permitida, se isso for mais elegante.
sed
proposta Eu apenas pensei OMG ...awk: illegal statement
.brew install mawk
e alterar o comando paramawk
funciona embora.De scripts úteis de uma linha para sed .
fonte
find . -type f -name '*.js' -exec sed --in-place -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
find . -type f -name '*.js' -exec sed -i '' -e :a -e '/^\n*$/{$d;N;};/\n$/ba' {} \;
Como você já tem respostas com as ferramentas mais adequadas sed e awk; você pode aproveitar o fato de
$(< file)
remover linhas em branco à direita.Esse hack barato não funcionaria para remover as linhas em branco à direita, que podem conter espaços ou outros caracteres não imprimíveis, apenas para remover as linhas vazias à direita. Também não funcionará se o arquivo contiver bytes nulos.
Em shells diferentes de bash e zsh, use em
$(cat file)
vez de$(<file)
.fonte
$()
descarta novas linhas à direita. Essa é uma decisão de design. Suponho que isso facilite a integração em outras strings:echo "On $(date ...) we will meet."
seria ruim com a nova linha que quase todo comando shell gera no final.[[ $a == '' ]] || printf '%s\n' "$a" >"$file"
.a=$(gtac file.txt); printf '%s\n' "$a" | gtac > file.txt
Você pode usar esse truque com
cat
&printf
:Por exemplo
O
$
indica o final de uma linha.Referências
fonte
Esta pergunta está marcada com ed , mas ninguém propôs uma
ed
solução.Aqui está um:
ou equivalente,
ed
colocará você na última linha do buffer de edição por padrão na inicialização.O primeiro comando (
a
) adiciona uma linha vazia ao final do buffer (a linha vazia no script de edição é essa linha e o ponto (.
) é apenas para retornar ao modo de comando).O segundo comando (
?
) procura a linha anterior mais próxima que contém algo (até caracteres de espaço em branco) e exclui tudo até o final do buffer a partir da próxima linha.O terceiro comando (
w
) grava o arquivo de volta no disco.A linha vazia adicionada protege o restante do arquivo de ser excluído no caso de não haver linhas vazias no final do arquivo original.
fonte
Aqui está uma solução Perl que não requer a leitura de mais de uma linha na memória por vez:
ou, como uma linha:
Isso lê o arquivo uma linha de cada vez e verifica cada linha para ver se contém um caractere que não seja de nova linha. Caso contrário, incrementa um contador; se o fizer, imprime o número de novas linhas indicadas pelo contador, seguidas pela própria linha e, em seguida, redefine o contador.
Tecnicamente, até o buffer de uma única linha na memória é desnecessário; seria possível resolver esse problema usando uma quantidade constante de memória lendo o arquivo em pedaços de comprimento fixo e processando-o caractere por caractere usando uma máquina de estado. No entanto, suspeito que seria desnecessariamente complicado para o caso de uso típico.
fonte
Se o seu arquivo for pequeno o suficiente para armazenar na memória, você poderá usar este
fonte
Em python (eu sei que não é o que você deseja, mas é muito melhor, pois é otimizado e um prelúdio para a versão do bash) sem reescrever o arquivo e sem ler todo o arquivo (o que é bom se o arquivo for muito grande):
Observe que ele não funciona em arquivos onde o caractere EOL não é '\ n'.
fonte
Uma versão bash, implementando o algoritmo python, mas menos eficiente, pois precisa de muitos processos:
fonte
Este é rápido de digitar e, se você conhece o sed, fácil de lembrar:
Ele usa o script sed para excluir as principais linhas em branco dos scripts úteis de uma linha para sed , referenciados por Alexey acima e tac (reverse cat).
Em um teste rápido, em um arquivo de linha de 18MB e 64.000 linhas, a abordagem de Alexey foi mais rápida (0,036 vs 0,046 segundos).
fonte