Есть ли команда Unix для добавления некоторых строковых данных в текстовый файл?
Что-то вроде:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Есть ли команда Unix для добавления некоторых строковых данных в текстовый файл?
Что-то вроде:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Ответы:
sed -i.old '1s;^;to be prepended;' inFile
-i
записывает изменение на место и делает резервную копию, если задано какое-либо расширение. (В этом случае .old
)1s;^;to be prepended;
заменяет начало первой строки заданной строкой замены, используя ;
в качестве разделителя команд.\n
после добавления; в зависимости от их потребностей. Аккуратное решение.
inFile
включить каталоги в свой путь?
\n
. Надо было сначала прочитать комментарии. Черт.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
и это испортилось, поскольку оно преобразует \t
и \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Я удивлен, что никто об этом не упомянул.
cat <(echo "before") text.txt > newfile.txt
что, возможно, более естественно, чем принятый ответ (распечатать что-то и передать это в команду подстановки лексикографически нелогично).
... и захватить то, что сказал Райан выше, при этом sponge
вам не нужен временный файл:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
РЕДАКТИРОВАТЬ: Похоже, это не работает в Bourne Shell /bin/sh
Используя здесь-строку - <<<
, вы можете:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
и <<< "to be prepended" < text.txt
конструкция не работает в Баше; они требуют zsh.
Это одна из возможностей:
(echo "to be prepended"; cat text.txt) > newfile.txt
вам, вероятно, нелегко обойтись с промежуточным файлом.
Альтернативы (может быть обременительным с экранированием оболочки):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. Если подумать, я не уверен, что мое связано, поэтому я отправляю отдельный ответ.
Это будет работать для формирования вывода. - означает стандартный ввод, который предоставляется через канал от echo.
echo -e "to be prepended \n another line" | cat - text.txt
Чтобы перезаписать файл, требуется временный файл, так как он не может вернуться во входной файл.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
как требуется , но отображает его на stdout. Вывод может быть направлен в другой файл, если это сработает для OP
Предпочитаю ответ Адама
Мы можем упростить использование губки . Теперь нам не нужно создавать временный файл и переименовывать его на
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Примечание:
Это может иметь неожиданные побочные эффекты, в частности, потенциальную замену символической ссылки на обычный файл, получение различных разрешений на файл и изменение даты создания (рождения) файла.
sed -i
, как и в ответе принца Джона Уэсли , пытается хотя бы восстановить исходные разрешения, но применяются и другие ограничения.
Вот простая альтернатива, использующая временный файл (он позволяет избежать чтения всего входного файла в память, как это делает решение shime ):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
Использование групповой команды ( { ...; ...; }
) немного более эффективно, чем использование подоболочки ( (...; ...)
), как в решении 0xC0000022L .
Преимущества:
Легко контролировать, следует ли добавлять новый текст непосредственно к первой строке или его следует вставлять как новую строку (строки) (просто добавьте \n
к printf
аргументу).
В отличие от sed
решения, работает, если входной файл пуст ( 0
байтов).
sed
Решение может быть упрощена , если намерение состоит в том, чтобы предварять один или несколько целых строк в существующий контент (предполагая , что входной файл не является пустым):
sed
«S i
функция вставки целые строки:
С GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
Портативный вариант, который также работает с macOS / BSD sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Обратите внимание, что буквальный перевод строки после символа \
является обязательным.
Используя почтенную ed
утилиту POSIX :
Примечание:
ed
всегда сначала считывает входной файл в память целиком .Чтобы добавить непосредственно к первой строке (как и в случае sed
, это не сработает, если входной файл полностью пуст ( 0
байты)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
ed
сообщения о статусе пользователя suppressed .ed
в виде многострочного файла here-document ( <<EOF\n...\nEOF
), то есть через стандартный ввод ; По умолчанию раскрытие строки будет выполнено в таких документах (оболочки переменной интерполяции); заключите в кавычки открывающий разделитель, чтобы скрыть это (например, <<'EOF'
).1
делает 1-ю строку текущей строкойs
выполняет замену строки на основе регулярного выражения в текущей строке, как в sed
; вы можете включать буквальные символы новой строки в текст замены, но они должны быть \
экранированы.w
записывает результат обратно во входной файл (для тестирования замените w
на, ,p
чтобы только распечатать результат, без изменения входного файла).Чтобы добавить одну или несколько целых строк :
Как и в случае sed
, i
функция неизменно добавляет завершающую новую строку к вставляемому тексту.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
делает 0
(начало файла) текущей строкой и запускает режим вставки ( i
); обратите внимание, что номера строк иначе основаны 1
на..
отдельной строкой.Наверное, ничего встроенного, но вы можете довольно легко написать свой собственный, например:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Что-то вроде этого хотя бы ...
$$
для производственного кода использования недостаточно (атака по символическим ссылкам Google); но это определенно лучше, чем статическое имя файла.
mktemp
В некоторых случаях добавленный текст может быть доступен только из stdin. Тогда эта комбинация будет работать.
echo "to be prepended" | cat - text.txt | tee text.txt
Если вы хотите опустить tee
вывод, добавьте > /dev/null
.
tee
он не треснет text.txt
до того, как cat
его прочитают? Я думаю, что нет - что сделало бы это решение опасным для здоровья файла.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Если lenA
это 1000000 (файл 1 lenB
Мб ) и 10000 (добавление текста 10 Кб), то файл «a.txt» перезаписывается 20 КБ букв «b». Это полностью сломано. Теперь, если вы используете 1 МБ a.txt и 1 МБ текста для добавления, tee
переходит в цикл, генерирующий файл размером 7 ГБ +, мне пришлось остановить команду. Итак, очевидно, что для больших размеров результат непредсказуем. У меня нет информации, должно ли это работать на небольших размерах.
Решение:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Обратите внимание, что это безопасно для всех типов входов, потому что нет расширений. Например, если вы хотите добавить в начало !@#$%^&*()ugly text\n\t\n
, это просто сработает:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
Последняя часть, которую нужно рассмотреть, - это удаление пробелов в конце файла во время подстановки команд "$(cat file.txt)"
. Все обходные пути относительно сложны. Если вы хотите сохранить символы новой строки в конце файла .txt, см. Это: https://stackoverflow.com/a/22607352/1091436
file.txt
больше, чем может быть помещено в список аргументов printf
.
Другой способ использования sed
:
sed -i.old '1 {i to be prepended
}' inFile
Если добавляемая строка является многострочной:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
- или это разрешено только для GNU sed?
sed
, за i
командой следует обратная косая черта и новая строка , и каждая строка ввода, кроме последней, также заканчивается обратной косой чертой. GNU sed
допускает сокращения в соответствии с тем, о чем вы спрашиваете, но это sed
делает только GNU » .
Как проверено в Bash (в Ubuntu), при запуске с тестового файла через;
echo "Original Line" > test_file.txt
можно выполнить;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
или, если версия bash слишком старая для $ (), вы можете использовать обратные кавычки;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
и получите следующее содержимое «test_file.txt»;
New Line
Original Line
Никакого промежуточного файла, просто bash / echo.
Еще одно довольно простое решение:
$ echo -e "string\n" $(cat file)
cat
расширения параметра в двойных кавычках - довольно веская причина для отрицательного голоса . Этот код разбивает содержимое файла на слова и передает каждое из этих слов в качестве отдельного аргумента echo
. Вы теряете исходные границы аргументов, вы теряете символы новой строки / табуляции / и т. Д., А строки, подобные \t
и \n
в исходном тексте, заменяются табуляциями и новыми строками вместо того, чтобы оставаться в прежнем виде.
Если вам нравится vi / vim, это может быть больше в вашем стиле.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Я бы рекомендовал определить функцию, а затем импортировать и использовать ее там, где это необходимо.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Тогда используйте это так:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Тогда содержимое вашего файла будет:
This is second
This is first
Я собираюсь использовать этот подход для реализации средства обновления журнала изменений.