Bash. Как добавить строку в начало текстового файла, не читая ее целиком?

Я могу придумать несколько сценариев.

  1. zshнет в /etc/shells,и OP хочет использовать его без ввода zshв командной строке. Возможные решения.

    a )использовать трюки профиля, чтобы выполнить его при входе в систему. Это так же эффективно, как изменение оболочки.

    b )попросить администратора добавить zshк /etc/shells, чтобы вы могли chshк нему

    c )умоляю админа сменить оболочку. это неразумно, потому что вы потеряете способность ftp. вы можете использовать ftp, только если у вас есть снаряд в/etc/shells

  2. пользователь хочет выйти из ограниченной оболочки, скорее всего, rbashили rsh.

    Если .profileдоступен для редактирования, PATHможно расширить, отредактировав его. Как только /binокажется в пути, вы можете запустить bashизнутри rsh/rbash, получив доступ к команде chsh, позволяющей менять оболочки. Многие команды имеют escape-последовательности оболочки, которые можно использовать для выхода из ограниченной оболочки и восстановления доступа к chsh.

  3. chshдействительно не работает по какой-то другой причине. решение а из возможности 1 является ответом и здесь.

Сценарий 2 является единственной причиной, по которой действительно нужно изменить оболочку по умолчанию (, она слишком ограничена ).

-1
23.11.2019, 17:19
6 ответов

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

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».

1
28.01.2020, 05:07

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

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

И, как говорит @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.
1
28.01.2020, 05:07

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

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, в обычных условиях, но ваша ситуация необычная.

0
28.01.2020, 05:07

Вам придется прочитать весь файл, чтобы добавить что-нибудь в начало файла. Однако вам не нужно считывать его в память, что делает ваша команда sed.

Самым простым решением было бы просто объединить новое содержимое с существующим файлом, чтобы создать новый файл, а затем заменить исходный файл этим:

printf '%s\n' "new contents" | cat - test.txt >new-test.txt
mv new-test.txt test.txt

Здесь catсначала будет читать из своего стандартного потока ввода (из printfили любой другой команды, которую вы можете использовать ), а затем из старого файла test.txt. Вывод пойдет в файл new-test.txt(, который будет создан или усечен, если он существовал ранее ).

Если вам абсолютно необходимо использовать для этого sed:

sed '1i\
new contents
' test.txt >new-test.txt &&
mv new-test.txt

Это запускает команду вставки(i)в первую строку файла и вставляет новое содержимое перед ней. Затем выводится остальная часть старого файла. Результат, как и прежде, записывается в new-test.txt, который впоследствии мог заменить исходный файл.

Хотели бы вы сделать редактирование в -месте и иметь GNU sed, вы могли бы написать его немного аккуратнее:

sed -i '1i new content' test.txt

В GNU sedможно было вставлять несколько строк, используя \nв качестве новой строки:

sed -i '1i new content\nsecond line' test.txt

Со стандартным sedвы будете делать

sed '1i\
new content\
second line
' test.txt >new-test.txt &&
mv new-test.txt test.txt
1
28.01.2020, 05:07

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

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

Или использовать ed

echo '0a
your text here
.
w' | ed some_file
0
28.01.2020, 05:07

Вы можете создать новый файл, содержащий «hello world», а затем добавить в него содержимое файла размером 1 Гб, используя DD (, который не будет читать весь файл сразу ).

echo -n 'hello world' > new_file.txt | dd if='1gb.txt' of='new_file.txt' bs=1 seek=$(wc -c <new_file.txt) && rm 1gb.txt

Источник:https://jamesdanielmarrsritchey.blogspot.com/2019/11/memory-friendly-way-of-prepending-data.html

0
28.01.2020, 05:07

Теги

Похожие вопросы