Я использую 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
Но я задавался вопросом, был ли стандартный способ перенаправить вывод в тот же файл, которые вводят, был взят от.
Я обычно использую 3-й способ, но с важным изменением :
$ sed 's / cat / dog /' манипулировать> tmp && mv tmp манипулировать
Т.е. измените ;
на &&
, чтобы перемещение происходило только в случае успешного выполнения команды sed; иначе вы потеряете исходный файл, как только сделаете опечатку в синтаксисе sed.
Примечание! Для тех, кто читает заголовок и пропускает ограничение OP «мой sed не поддерживает -i
» : для большинства людей sed будет поддерживать -i
, поэтому лучший способ сделать это:
$ sed -i 's / cat / dog /' manage
Если вы не хотите перемещать копии, вы можете использовать ed:
ed file.txt <<EOF
%s/cat/dog/
wq
EOF
Керниган и Пайк в Искусство программирования Unix обсуждают этот вопрос. Их решение - написать сценарий под названием overwrite
, который позволяет делать такие вещи.
Использование: перезаписать
файл
cmd
файл
.
# 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
Если заменить
в вашем $ PATH
, это также позволит вам сказать:
replace cat dog manipulate
Обходной путь с использованием дескрипторов открытых файлов:
exec 3<manipulate
Предотвратить усечение открытого файла:
rm manipulate
sed 's/cat/dog/' <&3 > manipulate
Возможно, -i
- это gnu sed или просто старая версия sed, но в любом случае. Вы на правильном пути. Первый вариант, вероятно, самый распространенный, третий вариант - если вы хотите, чтобы он работал везде (включая машины Solaris) ... :) Это «стандартные» способы сделать это.
-i
параметр недоступен в стандартном sed
.
Ваши альтернативы - это ваш третий путь или perl
.