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), который, я не уверен, можно включить в этот подход с временными файлами…?


person Henrik    schedule 18.10.2011    source источник
comment
этот пост должен помочь вам, используйте поиск перед публикацией нового вопроса   -  person user973254    schedule 18.10.2011
comment
@hced. Вам не нужно echo `date...` ... date... достаточно одного   -  person Peter.O    schedule 18.10.2011


Ответы (6)


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

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

Это работает путем создания выходного файла:

Допустим, у нас есть исходное содержимое файла file.txt.

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

Итак, file.txt — это наш «нижний» текстовый файл. Теперь добавьте в новый «выходной» файл

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

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

mv output.txt file.txt
cat file.txt
person mimoralea    schedule 22.07.2014

Единственный простой и безопасный способ изменить входной файл с помощью инструментов 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"
person Peter.O    schedule 18.10.2011
comment
Как/где я могу получить губку, если я использую Darwin UNIX (OS X)? - person Henrik; 18.10.2011
comment
Как изменение индекса делает символическую ссылку недействительной? Я предполагаю, что вы имеете в виду, что это делает недействительными жесткие ссылки. - person Mark Edgar; 19.10.2011
comment
@Mark Edgar: я ошибся. Проблема возникает, когда вы действуете по ссылке.. Я исправил ответ..... @hced: Я понятия не имею конкретно о Дарвине, но вот ссылка на moreutils... - person Peter.O; 20.10.2011
comment
@hced Если у вас есть MacPort, вы можете использовать port install moreutils - person Max Nanasy; 31.07.2013
comment
homebrew также имеет губку в пакете moreutils. brew install moreutils [2.2.3] ==› Загрузка homebrew.bintray.com/bottles/ - person Jesse Sanford; 24.11.2015

Самый простой способ IMO - использовать эхо и кошку:

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

Но это уже не самый эффективный способ...

person J V    schedule 18.10.2011
comment
Так не пойдет. Он начнет с усечения файла, а затем попытается прочитать его. - person Hasturkun; 18.10.2011
comment
Я использовал его раньше (старый добрый трюк cat image.jpg secret.zip > image.jpg) Редактировать: Упс, должно быть, использовал другой, да, сотрите этот ответ. - person J V; 18.10.2011
comment
Попробуйте, оболочка сначала открывает файл для записи, обрезает его, затем запускает cat (что в моей системе заставляет cat жаловаться, что входной файл является выходным файлом), в результате чего файл содержит только содержимое второго файла. - person Hasturkun; 18.10.2011
comment
Это работает. Проверьте сами на себе. Некоторые люди любят комментировать, не пытаясь для себя. - person mimoralea; 22.07.2014

Попробуйте этот http://www.unix.com/shell-programming-scripting/42200-add-text-beginning-file.html На мой взгляд, прямого оператора или команды нет. Для получения эффекта вы используете echo, cat и mv.

person SidJ    schedule 18.10.2011
comment
Вы можете включить хотя бы часть информации по этой ссылке, вы можете увидеть Как ответить и meta.stackexchange.com/q/8231/20270 - person Hasturkun; 18.10.2011

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

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

person Mark Edgar    schedule 18.10.2011