Перенаправить вывод из файла sed 's/c/d/' myFile в myFile

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

% 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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

sed -i "" 's/old/new/g' file   # FreeBSD sed

Ответ 3

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

ed file.txt <<EOF
%s/cat/dog/
wq
EOF

Ответ 4

Керниган и Пайк в "Искусстве программирования Unix" обсуждают эту проблему. Их решение состоит в том, чтобы написать script, называемый 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 "[email protected]" >$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

Как только у вас есть script в $PATH, вы можете сделать:

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

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

# 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 "[email protected][email protected][email protected]" $i
done

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

replace cat dog manipulate

Ответ 5

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

sed "s/cat/dog/" manipulate | sponge manipulate

Ответ 6

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

Ответ 7

Чтобы изменить несколько файлов (и сохранить резервную копию каждого из них как .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)

Ответ 8

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

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

Ответ 9

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

$ echo "111 222 333" > file.txt
$ sed -i -s s/222/444/ file.txt 
$ cat file.txt
111 444 333
$ 

Ответ 10

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

exec 3<manipulate 

Предотвратить усечение открытого файла:

rm manipulate
sed 's/cat/dog/' <&3 > manipulate