Перенаправить вывод из sed 's / c / d /' myFile в myFile - PullRequest
18 голосов
/ 06 апреля 2010

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

% sed -i 's/cat/dog/' manipulate
sed: illegal option -- i

Однако, как вы можете видеть, у моего sed нет этой команды.

Я пробовал это:

% sed 's/cat/dog/' manipulate > manipulate

Но это просто превращает манипуляции в пустой файл (имеет смысл).

Это работает:

% sed 's/cat/dog/' manipulate > tmp; mv tmp manipulate

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

Ответы [ 10 ]

37 голосов
/ 06 апреля 2010

Я обычно использую 3-й способ, но с важным изменением :

$ sed 's/cat/dog/' manipulate > tmp && mv tmp manipulate

т.е. измените ; на &&, чтобы перемещение происходило только в случае успеха sed; в противном случае вы потеряете исходный файл, как только сделаете опечатку в синтаксисе sed.

Примечание! Для тех, кто читает заголовок и пропускает ограничение OP "my sed не поддерживает -i" : Для большинства людей sed поддерживает -i, так что лучший способ сделать это:

$ sed -i 's/cat/dog/' manipulate

8 голосов
/ 01 июля 2011

Да, -i также поддерживается в FreeBSD / MacOSX sed, но для редактирования файла на месте нужна пустая строка.

sed -i "" 's/old/new/g' file   # FreeBSD sed
6 голосов
/ 07 апреля 2010

Если вы не хотите перемещать копии, вы можете использовать ed:

ed file.txt <<EOF
%s/cat/dog/
wq
EOF
3 голосов
/ 06 апреля 2010

Керниган и Пайк в Искусство программирования Unix обсуждают эту проблему. Их решение - написать скрипт под названием overwrite, который позволяет делать такие вещи.

Использование: overwrite file cmd file.

# overwrite: copy standard input to output after EOF

opath=$PATH
PATH=/bin:/usr/bin

case $# in
0|1)   echo 'Usage: overwrite file cmd [args]' 1>&2; exit 2
esac

file=$1; shift
new=/tmp/overwr1.$$; old=/tmp/overwr2.$$
trap 'rm -f $new $old; exit 1' 1 2 15  # clean up

if PATH=$opath "$@" >$new
then
       cp $file $old           # save original
       trap '' 1 2 15          # wr are commmitted
       cp $new $file
else
       echo "overwrite: $1 failed, $file unchanged" 1>&2
       exit 1
fi
rm -f $new $old

Как только у вас есть вышеуказанный скрипт в вашем $PATH, вы можете сделать:

overwrite manipulate sed 's/cat/dog/' manipulate

Чтобы сделать вашу жизнь проще, вы можете использовать replace скрипт из той же книги:

# replace: replace  str1 in files with str2 in place
PATH=/bin:/usr/bin

case $# in
    0|2) echo 'Usage: replace str1 str2 files' 1>&2; exit 1
esac

left="$1"; right="$2"; shift; shift

for i
do
    overwrite $i sed "s@$left@$right@g" $i
done

Наличие replace в вашем $PATH также позволит вам сказать:

replace cat dog manipulate
2 голосов
/ 23 июля 2011

Вы можете использовать sponge из moreutils .

sed "s/cat/dog/" manipulate | sponge manipulate
1 голос
/ 21 июня 2013

Чтобы изменить несколько файлов (и сохранить резервную копию каждого как * .bak):

perl -p -i -e "s / oldtext / newtext / g" *

replaces any occurence of oldtext by newtext in all files in the current folder. However you will have to escape all perl special characters within oldtext and newtext using the backslash 

This is called a “Perl pie” (mnemonic: easy as a pie)
The -i flag tells it do do in-place replacement, and it should be ok to use single (“'”) as well as double (“””) quotes.

    If using ./* instead of just *, you should be able to do it in all sub-directories 
See man perlrun for more details, including how to take a backup file of the original.
using sed:
            sed -i    's/old/new/g' ./*  (used in GNU)
    sed -i '' 's/old/new/g' ./*  (used in FreeBSD)
1 голос
/ 06 апреля 2010

Возможно, -i - это gnu sed или просто старая версия sed, но в любом случае. Вы на правильном пути. Первый вариант, вероятно, самый распространенный, третий вариант, если вы хотите, чтобы он работал везде (включая машины Solaris) ... :) Это «стандартные» способы сделать это.

0 голосов
/ 16 января 2015

Много ответов, но ни один из них не верен. Вот правильный и самый простой:

$ echo "111 222 333" > file.txt
$ sed -i -s s/222/444/ file.txt 
$ cat file.txt
111 444 333
$ 
0 голосов
/ 06 апреля 2010

Обходной путь, используя дескрипторы открытого файла:

exec 3<manipulate 

Запрет усечения открытого файла:

rm manipulate
sed 's/cat/dog/' <&3 > manipulate
0 голосов
/ 06 апреля 2010

-i опция недоступна в стандартной комплектации sed.

Ваши альтернативы - ваш третий путь или perl.

...