Unix: Как я могу добавить вывод в файл?

В частности, я использую комбинацию >> и tee в пользовательском псевдониме для хранения новых обновлений Homebrew в текстовом файле, а также вывода на экране:

alias bu="echo `date "+%Y-%m-%d at %H:%M"` \
    >> ~/Documents/Homebrew\ Updates.txt && \
    brew update | tee -a ~/Documents/Homebrew\ Updates.txt"

Вопрос. Что делать, если я хочу добавить этот вывод в свой текстовый файл, то есть разместить его в начале файла, а не добавлять его в конец?


Edit1. Как сообщалось в ответах ниже, использование временных файлов может быть хорошим подходом, который по крайней мере частично помог мне:

targetLog="~/Documents/Homebrew\ Updates.txt"
alias bu="(brew update | cat - $targetLog \
> /tmp/out1 && mv /tmp/out1 $targetLog \
&& echo `date "+%Y-%m-%d at %H:%M":%S` | \
cat - $targetLog > /tmp/out2 \
&& mv /tmp/out2 $targetLog)"

Но проблема в том, что вывод в STDOUT (ранее сделанный возможным для tee), который я не уверен, может быть включен в этот подход tempfile...?

Ответ 1

sed с радостью сделает это за вас, используя -i для редактирования на месте, например.

sed -i -e "1i `date "+%Y-%m-%d at %H:%M"`" some_file

Ответ 2

Это работает, создавая выходной файл:

Скажем, у нас есть начальное содержимое файла file.txt

echo "first line" > file.txt          
echo "second line" >> file.txt

Итак, file.txt - это наш "нижний" текстовый файл. Теперь добавьте новый файл 'output'

echo "add new first line" | cat - file.txt > output.txt # <--- Just this command

Теперь выход имеет содержимое так, как мы хотим. Если вам нужно ваше старое имя:

mv output.txt file.txt
cat file.txt

Ответ 3

Единственный простой и безопасный способ изменения входного файла с помощью инструментов bash - использовать временный файл, например. sed -i использует временный файл за кулисами (но для надежного sed требуется больше).

Некоторые из используемых методов имеют тонкую ловушку "может сломать вещи", когда вместо запуска вашей команды в реальном файле данных вы запускаете ее по символической ссылке (в файл, который вы собираетесь изменить). Если это не правильно, это может сломать ссылку и преобразовать ее в реальный файл, который получает моды и оставляет исходный реальный файл без предполагаемых модов и без символической ссылки (без ошибок выхода из кода)

Чтобы избежать этого с помощью sed, вам нужно использовать опцию --follow-symlinks.
Для других методов просто имейте в виду, что он должен следовать символическим ссылкам (когда вы действуете по такой ссылке)
Используя временный файл, rm temp file работает только в том случае, если "файл" не является символической ссылкой.

Один безопасный способ - использовать sponge из пакета moreutils

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

sponge - хороший общий способ справиться с такой ситуацией.

Вот пример, используя sponge

hbu=~/'Documents/Homebrew Updates.txt'
{ date "+%Y-%m-%d at %H:%M"; cat "$hbu"; } | sponge "$hbu"

Ответ 4

Простейшим способом ИМО было бы использовать эхо и кошку:

echo "Prepend" | cat - inputfile > outputfile

Или для вашего примера в основном замените tee -a ~/Documents/Homebrew\ Updates.txt на cat - ~/Documents/Homebrew\ Updates.txt > ~/Documents/Homebrew\ Updates.txt

Изменить: Как указано в hasturkun, это не сработает, попробуйте:

echo "Prepend" | cat - file | tee file

Но это не самый эффективный способ сделать это больше...

Ответ 6

{ date; brew update |tee /dev/tty; cat updates.txt; } >updates.txt.new
mv updates.txt.new updates.txt

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