sed редактировать файл на месте



Я пытаюсь выяснить, можно ли редактировать файл в одной команде sed без вручную потоковая передача отредактированного содержимого в новый файл, а затем переименование нового файла в исходное имя файла. Я попробовал -i вариант, но моя система Solaris сказала, что -i является незаконным вариантом. Есть ли другой способ?

649   13  

13 ответов:

The -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 с баром в файле образца. Резервная копия исходного файла будет сохранена в образце.бак

для редактирования 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:

патчу не нужно знать, к какому файлу обращаться, так как он находится в первой строке вывода из 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 до 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 со старым содержимым.

если вы не хотите хранить копию, просто не передавайте параметр расширения.

вы могли бы использовать vi

vi -c '%s/foo/bar/g' my.txt -c 'wq'
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 /' {} \;

Comments

    Ничего не найдено.