Adicione linhas ao início e ao final do arquivo enorme

23

Eu tenho o cenário em que as linhas serão adicionadas no início e no final dos arquivos grandes.

Eu tentei como mostrado abaixo.

  • para a primeira linha:

    sed -i '1i\'"$FirstLine" $Filename
    
  • para a última linha:

    sed -i '$ a\'"$Lastline" $Filename  
    

Mas o problema com esse comando é que ele está anexando a primeira linha do arquivo e percorrendo o arquivo inteiro. Na última linha, ele está novamente percorrendo o arquivo inteiro e acrescentando uma última linha. Desde o seu enorme arquivo (14GB) isso está demorando muito tempo.

Como posso adicionar uma linha ao início e outra ao final de um arquivo, enquanto apenas leio o arquivo uma vez?

    
por UNIXbest 22.08.2013 / 13:17

7 respostas

18

sed -i usa os arquivos temporários como um detalhe de implementação, que é o que você está experimentando; no entanto, a inclusão de dados no início de um fluxo de dados sem sobrescrever o conteúdo existente requer a regravação do arquivo. Não há como contornar isso, mesmo evitando sed -i .

Se reescrever o arquivo não for uma opção, você pode considerar manipulá-lo quando for lido, por exemplo:

{ echo some prepended text ; cat file ; } | command

Além disso, o sed é para edição de fluxos - um arquivo não é um fluxo. Use um programa destinado a esse propósito, como ed ou ex. A opção -i para o sed não é apenas não portável, ele também irá quebrar quaisquer links simbólicos para o seu arquivo, uma vez que essencialmente o exclui e recria, o que é inútil.

Você pode fazer isso em um único comando com ed da seguinte forma:

ed -s file << 'EOF'
0a
prepend these lines
to the beginning
.
$a
append these lines
to the end
.
w
EOF

Note que, dependendo da sua implementação, ele pode usar um arquivo de paginação, exigindo que você tenha pelo menos esse espaço disponível.

    
por 22.08.2013 / 13:29
9

Observe que, se você quiser evitar alocar uma cópia inteira do arquivo no disco, poderá fazer isso:

sed '
1i\
begin
$a\
end' < file 1<> file

Isso usa o fato de que quando seu stdin / stdout é um arquivo, sed lê e escreve por bloco. Então, aqui está tudo bem substituir o arquivo que está lendo desde que a primeira linha que você está adicionando seja menor que o tamanho do bloco de sed (deve ser algo como 4k ou 8k).

Note que, se por algum motivo sed falhar (morto, travamento de máquina ...), você terminará com o arquivo parcialmente processado, o que significará alguns dados do tamanho da primeira linha faltando em algum lugar no meio .

Observe também que, a menos que seu sed seja o GNU sed , isso não funcionará para dados binários (mas como você está usando -i , você está usando o GNU sed).

    
por 22.08.2013 / 15:17
4

Aqui estão algumas opções (todas as quais criarão uma nova cópia do arquivo, portanto, verifique se você tem espaço suficiente para isso):

  • eco simples / cat

    echo "first" > new_file; cat $File >> new_file; \
      echo "last" >> new_file; 
    
  • awk / gawk etc

    gawk 'BEGIN{print "first\n"}{print}END{print "last\n"}' $File > NewFile 
    

    awk e seus arquivos de leitura linha por linha. O bloco BEGIN{} é executado antes da primeira linha e o bloco END{} após a última linha. Então, o comando acima significa print "first" at the beginning, then print every line in the file and print "last" at the end .

  • Perl

    perl -ne 'BEGIN{print "first\n"} print;END{print "last\n"}' $File > NewFile
    

    Isto é essencialmente a mesma coisa que o gawk acima escrito em Perl.

por 22.08.2013 / 14:09
3

Não há como inserir dados no início de um arquivo, tudo o que você pode fazer é criar um novo arquivo, gravar os dados adicionais e anexar os dados antigos. Então você terá que reescrever o arquivo inteiro pelo menos uma vez para inserir a primeira linha. Você pode acrescentar a última linha sem reescrever o arquivo.

sed -i '1i\'"$FirstLine" $Filename
echo "$LastLine" >>$Filename

Alternativamente, você pode combinar os dois comandos em uma corrida de sed.

sed -i -e '1i\'"$FirstLine" -e '$ a\'"$Lastline" $Filename

sed -i cria um novo arquivo de saída e, em seguida, o move sobre o arquivo antigo. Isso significa que, enquanto o sed está funcionando, há uma segunda cópia do arquivo usando espaço. Você pode evitar isso por sobrescrevendo o arquivo no lugar , mas com grandes restrições: a linha que você está adicionando tem que ser menor que o buffer do sed, e se o seu sistema travar você terminará com um arquivo danificado e algum conteúdo perdido no meio, então eu recomendo strongmente contra isso.

    
por 23.08.2013 / 02:24
3

Eu prefiro o mais simples:

gsed -i '1s/^/foo\n/gm; $s/$/\nbar/gm' filename.txt

Isso transforma o arquivo:

asdf
qwer

para o arquivo:

foo
asdf
qwer
bar
    
por 15.06.2016 / 20:42
0
$ (echo "Some Text" ; cat file1) > file2
    
por 22.08.2014 / 23:31
0

Você pode usar o Vim no modo Ex:

ex -sc '1i|ALFA' -c '$a|BRAVO' -cx file
  1. 1 selecione a primeira linha

  2. i inserir texto e nova linha

  3. $ selecione a última linha

  4. a acrescentar texto e nova linha

  5. x salvar e fechar

por 17.04.2016 / 07:54