Como removo determinadas linhas (usando números de linhas) em um arquivo?

27

Existem linhas específicas que desejo remover de um arquivo. Digamos que seja a linha 20-37 e depois a linha 45. Como eu faria isso sem especificar o conteúdo dessas linhas?

tshepang
fonte
Qual é o tamanho do seu arquivo? Pode ser carregado na memória?
Faheem Mitha
Alguns kilobytes.
tshepang

Respostas:

29

Com sed, assim:

sed '20,37d; 45d' < input.txt > output.txt

Se você quiser fazer isso no local:

sed --in-place '20,37d; 45d' file.txt
pdo
fonte
Existe uma maneira de fazê-lo no local?
#
Sugiro sed -i file
enzotib
11
@Tshepang: Use ed, ou GNU sed -i, ou sponge, ou um método de arquivo grande .
Gilles 'SO- stop be evil'
3
Eu sempre me perguntei sobre o termo possivelmente enganoso no local , quando me referi a 'sed', então procurei em 'man sed': - in-place [= SUFFIX] This option specifies that files are to be edited in-place. GNU sed 'faz isso criando um arquivo temporário e enviando a saída para esse arquivo e não para a saída padrão.` ... Eu não conheço nenhum outro 'sed', mas a logística da atualização "no local" com um editor de fluxo não "calcula" :)
Peter.O
2
A maioria dos métodos "no local" usa um arquivo temporário, na minha experiência.
Faheem Mitha
5

Se o arquivo couber confortavelmente na memória, você também pode usá-lo ed.
Os comandos são bem parecidos com o sedacima, com uma diferença notável : você precisa passar a lista de números de linhas / faixas a serem excluídas em ordem decrescente (da linha mais alta sem / faixa para a mais baixa). O motivo é que, quando você exclui / insere / divide / une linhas ed, o buffer de texto é atualizado após cada subcomando, portanto, se você excluir algumas linhas, o restante das linhas a seguir não estará mais na mesma posição no buffer quando o o próximo subcomando é executado. Então você tem que começar de trás para frente 1 . Edição no
local :

ed -s in_file <<IN
45d
20,37d
w
q
IN

ou

ed -s in_file <<< $'45d\n20,37d\nw\nq\n'

ou

printf '%s\n' 45d 20,37d w q | ed -s in_file

Substitua write por ,print se desejar imprimir a saída resultante em vez de gravar no arquivo. Se você deseja manter intacto o arquivo original e gravar em outro arquivo, pode passar o novo nome do arquivo para o wsubcomando rite:

ed -s in_file <<IN
78,86d
65d
51d
20,37d
w out_file
q
IN

1 A menos que você esteja disposto a calcular os novos números de linha após cada dexclusão, o que é bastante trivial para este caso em particular (após excluir as linhas 20-37, ou seja, 18 linhas, a linha 45 se torna a linha 27) para que você possa executar:

ed -s in_file <<IN
20,37d
27d
w
q
IN

No entanto, se você precisar excluir vários números / faixas de linha, trabalhar para trás não é um acéfalo.

don_crissti
fonte
O qcomando é útil no final? Eu acho que sai de qualquer maneira.
Tom Fenech
@TomFenech - Nem todas as implementações saída de qualquer forma (embora a maioria fazer ... Eu não posso mais encontrar o fio, onde este assunto foi discutido ...)
don_crissti
1

Apenas leia na memória, altere e depois escreva de volta. Você pode fazer algo como

filename = "foo"
f = open(filename, 'r+')                                                                                                                                 
linenums = [1, 3]                                                                                                                                            
s = [y for x, y in enumerate(f) if x not in [line-1 for line in linenums]]                                                                                                                                          
f.seek(0)
f.write(''.join(s))
f.truncate(f.tell())
f.close()

Testado com um arquivo de 5 linhas. Créditos para http://pleac.sourceforge.net/pleac_python/fileaccess.html , consulte a seção "Modificando um arquivo no local sem um arquivo temporário". Consulte também https://stackoverflow.com/questions/125703/how-do-i-modify-a-text-file-in-python

Algumas notas:

  1. Pode-se primeiro truncar o arquivo, depois escrever nele, em vez de escrever e depois truncar, como acima. No entanto, não conheço um sinalizador Python que permita a leitura e, em seguida, faça uma gravação truncada. Mas talvez esteja faltando alguma coisa, pois o documento não está tão claro. O que me leva a

  2. Às vezes, a documentação do Python é realmente péssima. Consulte http://docs.python.org/library/functions.html#open

    Os modos 'r +', 'w +' e 'a +' abrem o arquivo para atualização (observe que 'w +' trunca o arquivo).

    Isso significa alguma coisa para você? O que diabos está "aberto para atualização"?

  3. Eu não sei se fazer isso em python em vez de algo unixy como o editor de fluxo é melhor. Pode ser mais portátil, mas não sei como o sed é portátil. Eu escrevi assim porque me sinto mais à vontade com a programação de baixo nível do que com as ferramentas clássicas do Unix, que são boas se elas fazem exatamente o que você deseja, mas (eu acho) geralmente são menos flexíveis.

  4. Essa abordagem (manipular o arquivo na memória) troca a memória por espaço em disco. Ele deve funcionar bem em máquinas com alguns Gb de memória para arquivos de até algumas centenas de Mb. O Python não lida com seqüências de caracteres com muita eficiência, portanto, mudar para C / C ++, por exemplo, aumentaria um pouco o desempenho e reduziria bastante o uso de memória.

Faheem Mitha
fonte
0

Você pode usar o Vim no modo Ex:

ex -sc '20,37d|45d|x' file
  1. d excluir

  2. x salvar e fechar

Steven Penny
fonte