Bash - Como posso adicionar uma string ao início de um arquivo de texto sem ler tudo?

Bash - Como posso adicionar uma string ao início de um arquivo de texto sem ler tudo?

estou tentando inserir uma string "hello world" antes de um arquivo de texto chamado "test.txt", já faço isso com sed, mas infelizmente o "comando sed" mata minha memória, pois lê um arquivo inteiro.

meu arquivo contém um texto com tamanho de 1gb e minha memória tem apenas 512 mb. como posso fazer isso?, algo assim:

echo --insert-before "hello world" >> test.txt

Ou qual operador devo usar para inseri-lo antes, algo assim:

echo "hello world" << test.txt

Ou outra ideia?

Obs: o operador >>para inserir texto no final funciona bem, não mata minha memória, mas preciso fazer ao contrário para iniciar o arquivo, sem substituir o conteúdo do meu arquivo de texto, sem nova linha.

aqui está o meu código real que usei:

echo "hello world" > test.txt;
echo "the large content that size is 1gb" >> test.txt;
sed -i ':a;N;$!ba;s/\n//g' test.txt;

Responder1

Você afirma que a sequência de comandos que você usou foi:

echo "hello world" > test.txt;
echo "the large content that size is 1gb" >> test.txt;
sed -i ':a;N;$!ba;s/\n//g' test.txt;

Presumirei que os comandos eram na verdade:

echo "hello world" > newfile;
cat test.txt >> newfile;            # assuming the file with 1GigaByte was test.txt

E você reclama do comando sed, que existe apenas para remover novas linhas (da sua descrição).

O mesmo poderia ser feito com tro qual não usa (muita) memória:

echo "hello world" > newfile;
cat test.txt | tr -d '\n' >> newfile

E newfileterá uma cópia do test.txt com "hello world" anexado.

Responder2

sednão usa muita memória. No entanto, o sistema operacional pode estar armazenando em cache o disco. Portanto, usar nocachepode ajudar (se o disco for rápido o suficiente ou se você não estiver lendo os mesmos dados mais de uma vez). E/ou use a --unbufferedopção de sed(para que seda confiança use o mínimo de memória possível).

Além disso, não pode haver opção de eco, como >>é feito pelo shell, não pelo comando. Diz ao shell para anexar o stdout do comando ao arquivo.

E como diz @Kusalananda, seu sedscript não é eficiente. Eu provavelmente usaria apenas cat.

uncache cat "<(echo the_prefix)" old_file_name > new_file_name
rm old_file_name
mv -T new_file_name old_file_name #note not all `mv`s have the `-T` option, it can unsafely be left out.

Responder3

Que tal algo um pouco mais simples?

cat <<_eof_ > file
Hello world!
$(cat file)
_eof_

Ou use ed

echo '0a
your text here
.
w' | ed some_file

Responder4

Se isso está matando sua memória:

sed -i ':a;N;$!ba;s/\n//g' "test.txt"

então, para remover novas linhas, mas ler apenas uma de cada vez, tente:

{
    printf "hello world"  # with no newline
    while IFS= read -r line || [ -n "$line" ]; do
        printf "%s" "$line"
    done < test.txt
    echo ""          # add a newline to the end of the file
} > test.txt.tmp && mv test.txt{.tmp,}

Isso será um pouco mais lento que o sed, em circunstâncias normais, mas sua situação está fora do comum.

informação relacionada