Оболочка один лайнер, чтобы подготовить к файлу - PullRequest
124 голосов
/ 10 сентября 2008

Это, вероятно, комплексное решение .

Я ищу простой оператор, такой как ">>", но для добавления.

Боюсь, его не существует. Я должен сделать что-то вроде

 mv myfile tmp
 cat myheader tmp > myfile

Что-нибудь умнее?

Ответы [ 32 ]

94 голосов
/ 10 сентября 2008

Это все еще использует временный файл, но по крайней мере он находится в одной строке:

echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile

Кредит: BASH: добавление текста / строк в файл

29 голосов
/ 17 июля 2010
echo '0a
your text here
.
w' | ed some_file

ed - Стандартный редактор! http://www.gnu.org/fun/jokes/ed.msg.html

27 голосов
/ 07 марта 2009

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}} тогда был быстрый ответ, который сработал и получил много голосов. Затем, когда вопрос стал более популярным и прошло больше времени, возмущенные люди начали сообщать, что это, конечно, работает, но могут случиться странные вещи, или это просто не сработало, поэтому какое-то время яростно опускали голос. Такое веселье.

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

Теперь, несмотря на все это, ответ был:


Создание другого файлового дескриптора для файла (exec 3<> yourfile), следовательно, запись в него (>&3), кажется, преодолевает дилемму чтения / записи в том же файле. У меня работает на 600К файлах с awk. Однако попытка использовать тот же трюк с помощью 'cat' не удалась.

Передача prepenage в качестве переменной в awk (-v TEXT="$text") преодолевает проблему буквальных кавычек, которая не позволяет выполнить этот трюк с помощью sed.

#!/bin/bash
text="Hello world
What's up?"

exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3
20 голосов
/ 02 мая 2010

Джон Ми: ваш метод не гарантированно сработает и, вероятно, потерпит неудачу, если вы добавите более 4096 байт (по крайней мере, так будет с gnu awk, но я полагаю, что другие реализации будут иметь аналогичные ограничения) В этом случае он не только потерпит неудачу, но и войдет в бесконечный цикл, где будет считывать свой собственный вывод, тем самым увеличивая размер файла до тех пор, пока не будет заполнено все доступное пространство.

Попробуйте сами:

exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3

(предупреждение: убейте его через некоторое время или оно заполнит файловую систему)

Кроме того, очень опасно редактировать файлы таким образом, и это очень плохой совет, так как если что-то случится во время редактирования файла (сбой, диск заполнен), вы почти гарантированно останетесь с файлом в несогласованном виде. состояние.

16 голосов
/ 10 сентября 2008

Невозможно без временного файла, но здесь идет переводчик

{ echo foo; cat oldfile; } > newfile && mv newfile oldfile

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

15 голосов
/ 12 сентября 2008

Стоит отметить, что часто хорошая идея - безопасно генерировать временный файл с помощью утилиты, такой как mktemp , по крайней мере, если скрипт когда-либо будет выполняться с root привилегии. Например, вы можете сделать следующее (снова в bash):

(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )
14 голосов
/ 30 марта 2013

Если вам это нужно на компьютерах, которыми вы управляете, установите пакет «moreutils» и используйте «sponge». Тогда вы можете сделать:

cat header myfile | sponge myfile
12 голосов
/ 13 февраля 2015

Используя bash heredoc, вы можете избежать необходимости в файле tmp:

cat <<-EOF > myfile
  $(echo this is prepended)
  $(cat myfile)
EOF

Это работает, потому что $ (cat myfile) вычисляется при оценке bash-скрипта перед выполнением cat с перенаправлением.

9 голосов
/ 16 июля 2009

при условии, что файл, который вы хотите отредактировать, - это my.txt

$cat my.txt    
this is the regular file

И файл, который вы хотите добавить, это заголовок

$ cat header
this is the header

Убедитесь, что в заголовочном файле есть последняя пустая строка.
Теперь вы можете добавить его к

$cat header <(cat my.txt) > my.txt

В итоге вы получите

$ cat my.txt
this is the header
this is the regular file

Насколько я знаю, это работает только в 'bash'.

9 голосов
/ 15 сентября 2008

Когда вы начинаете пытаться делать вещи, которые становятся трудными в shell-скрипте, я настоятельно рекомендую изучить переписывание скрипта на «правильном» языке скриптов (Python / Perl / Ruby / etc)

Что касается добавления строки к файлу, это невозможно сделать с помощью конвейера, поскольку, когда вы делаете что-то вроде cat blah.txt | grep something > blah.txt, он непреднамеренно очищает файл. Существует небольшая служебная команда под названием sponge, которую вы можете установить (вы делаете cat blah.txt | grep something | sponge blah.txt, и она буферизует содержимое файла, а затем записывает его в файл). Это похоже на временный файл, но вам не нужно делать это явно. но я бы сказал, что это «худшее» требование, чем, скажем, Perl.

Может быть способ сделать это с помощью awk или подобного, но если вам нужно использовать shell-скрипт, я думаю, что временный файл - самый простой (/ only?) Способ ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...