Bash — как добавить строку в начало текстового файла, не считывая его полностью?

Bash — как добавить строку в начало текстового файла, не считывая его полностью?

Я пытаюсь вставить строку «hello world» перед текстовым файлом с именем «test.txt». Я уже делаю это с помощью sed, но, к сожалению, «команда sed» убивает мою память, потому что она считывает весь файл.

Мой файл содержит текст размером 1 ГБ, а памяти у меня всего 512 МБ. Как мне это сделать?, что-то вроде этого:

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

Или какой оператор мне нужно использовать, чтобы вставить его раньше, что-то вроде этого:

echo "hello world" << test.txt

Или другая идея?

Примечание: оператор >>для вставки текста в конец работает нормально, он не убивает мою память, но мне нужно сделать это в обратном порядке для начала файла, не переопределяя содержимое моего текстового файла, без новой строки.

Вот мой реальный код, который я использовал:

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;

решение1

Вы утверждаете, что последовательность команд, которые вы использовали, была следующей:

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;

Я предполагаю, что команды на самом деле были такими:

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

И вы жалуетесь на команду sed, которая предназначена только для удаления новых строк (из вашего описания).

То же самое можно сделать с помощью tr, который не использует (много) памяти:

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

И newfileбудет иметь копию test.txt с добавленным в начало "hello world".

решение2

sedне использует много памяти. Однако ОС может кэшировать диск. Поэтому использование nocacheможет помочь (если диск достаточно быстрый или вы не считываете одни и те же данные более одного раза). И/или используйте опцию --unbuffered( sedчтобы sedReli использовал как можно меньше памяти).

Также не может быть опции echo, как >>это делает оболочка, а не команда. Она сообщает оболочке, что нужно добавить stdout команды в файл.

И как говорит @Kusalananda, ваш sedскрипт неэффективен. Я бы, наверное, просто использовал 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.

решение3

А как насчет чего-нибудь попроще?

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

Или используйте ed

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

решение4

Если это убивает вашу память:

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

затем, чтобы удалить новые строки и читать только по одной, попробуйте:

{
    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,}

В обычных обстоятельствах это будет немного медленнее, чем sed, но ваша ситуация нестандартная.

Связанный контент