sed редактировать файл на месте
Я пытаюсь выяснить, можно ли редактировать файл в одной команде sed без вручную потоковая передача отредактированного содержимого в новый файл, а затем переименование нового файла в исходное имя файла. Я попробовал -i
вариант, но моя система Solaris сказала, что -i
является незаконным вариантом. Есть ли другой способ?
13 ответов
на -i
опции потоки отредактированного контента в новый файл, а затем переименовывает его за кулисами, в любом случае.
пример:
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
и
sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
on macOS.
в системе, где sed
не имеет возможности редактировать файлы на месте, я думаю, что лучшим решением будет использовать perl
:
perl -pi -e 's/foo/bar/g' file.txt
хотя это создает временный файл, он заменяет оригинал, потому что был предоставлен пустой суффикс/расширение на месте.
обратите внимание, что в OS X вы можете получить странные ошибки, такие как "недопустимый код команды" или другие странные ошибки при выполнении этой команды. Чтобы устранить эту проблему, попробуйте
sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
это потому, что на OSX версии sed
на ждет extension
аргумент, поэтому ваша команда фактически анализируется как extension
аргумент и путь к файлу интерпретируются как код команды. Источник: https://stackoverflow.com/a/19457213
следующее отлично работает на моем mac
sed -i.bak 's/foo/bar/g' sample
мы заменяем foo на bar в файле образца. Резервная копия исходного файла будет сохранена в sample.бак!--3-->
для редактирования inline без резервного копирования используйте следующую команду
sed -i'' 's/foo/bar/g' sample
одно следует отметить,sed
не может писать файлы самостоятельно, поскольку единственная цель sed-выступать в качестве редактора в "потоке" (т. е. конвейерах stdin, stdout, stderr и других >&n
буферов, розетки и тому подобное). Имея это в виду, вы можете использовать другую команду tee
для записи результатов в файл. Другой вариант-создать патч из конвейера содержимого в diff
.
метод тройник
sed '/regex/' <file> | tee <file>
патч метод
sed '/regex/' <file> | diff -p <file> /dev/stdin | patch
обновление:
кроме того, обратите внимание, что патч получит файл для изменения из строки 1 вывода diff:
Patch не нужно знать, какой файл для доступа, так как это находится в первой строке вывода из diff:
$ echo foobar | tee fubar
$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar 2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin 2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar
$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar
невозможно сделать то, что вы хотите с sed
. Даже версии sed
в поддержку -i
опция для редактирования файла на месте сделать именно то, что вы явно заявили, что вы не хотите: они пишут во временный файл, а затем переименовать файл. Но, возможно, вы можете просто использовать ed
. Например, чтобы изменить все вхождения foo
to bar
в файле file.txt
, вы можете сделать:
echo ',s/foo/bar/g; w' | tr \; '2' | ed -s file.txt
синтаксис похож на sed
, но конечно не точно тот же.
но, возможно, вам следует подумать, почему вы не хотите использовать переименованный временный файл. Даже если у вас нет -i
поддержка sed
, вы можете легко написать сценарий, чтобы сделать работу за вас. Вместо sed -i 's/foo/bar/g' file
, вы могли бы сделать inline file sed 's/foo/bar/g'
. Такой сценарий тривиален для написания. Например:
#!/bin/sh -e
IN=
shift
trap 'rm -f $tmp' 0
tmp=$( mktemp )
<$IN "$@" >$tmp && cat $tmp > $IN # preserve hard links
должно быть достаточно для большинства применений.
sed поддерживает редактирование на месте. От man sed
:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
пример:
Допустим у вас есть файлhello.txt
С текстом:
hello world!
если вы хотите сохранить резервную копию старого файла, использовать:
sed -i.bak 's/hello/bonjour' hello.txt
вы получите два файла:hello.txt
содержание:
bonjour world!
и hello.txt.bak
со старым содержимым.
если вы не хотите, чтобы сохранить копию, просто не передать параметр расширения.
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
следует сохранить все жесткие ссылки, так как выходные данные направляются обратно для перезаписи содержимого исходного файла и избегают необходимости в специальной версии sed.
если вы заменяете такое же количество символов и после тщательного чтения "на месте" редактирование файлов...
вы также можете использовать оператор перенаправления <>
открыть файл для чтения и записи:
sed 's/foo/bar/g' file 1<> file
смотрите в прямом эфире:
$ cat file
hello
i am here # see "here"
$ sed 's/here/away/' file 1<> file # Run the `sed` command
$ cat file
hello
i am away # this line is changed now
С справочное руководство Bash → 3.6.10 Открытие дескрипторов файлов для чтения и записи:
оператор перенаправления
[n]<>word
вызывает файл, имя которого является расширением word, который будет открыт для чтение и запись в файловом дескрипторе n или в файловом дескрипторе 0 если N не указано. Если файл не существует, он создается.
вы не указали, какую оболочку вы используете, но с zsh вы можете использовать =( )
строительство, чтобы добиться этого. Что-то вроде:
cp =(sed ... file; sync) file
=( )
похож на >( )
но создает временный файл, который автоматически удаляется при cp
завершается.
Как сказал Манипенни в Skyfall: "иногда старые способы лучше." Позже Кинкейд сказал нечто подобное.
$ printf ', s/false/true | g\nw\n' / ed {YourFileHere}
счастливое редактирование на месте. Добавлена '\nw\n ' для записи файла. Прошу прощения за задержку с ответом на запрос.
очень хорошие примеры. У меня была проблема с редактированием многих файлов, и опция-i кажется единственным разумным решением, использующим ее в команде find. Здесь скрипт для добавления "version:" перед первой строкой каждого файла:
find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;