将输出从sed的/ c / d /'myFile重定向到myFile

时间:2010-04-06 14:13:48

标签: bash sed solaris redirect

我在脚本中使用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 个答案:

答案 0 :(得分:37)

我通常使用第三种方式,但重要更改

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

即。将;更改为&&,这样只有在sed成功时才会移动;一旦你用sed语法输入拼写错误,你就会丢失原始文件。

注意!对于那些阅读标题但缺少OP约束的人“我的sed不支持-i:对于大多数人来说,sed会支持-i,所以最好的方法是:

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

答案 1 :(得分:8)

是的,FreeBSD / MacOSX -i也支持sed,但需要空字符串作为参数来就地编辑文件。

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

答案 2 :(得分:6)

如果您不想移动副本,可以使用ed:

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

答案 3 :(得分:3)

Unix编程艺术中的Kernighan和Pike讨论了这个问题。他们的解决方案是编写一个名为overwrite的脚本,允许人们做这样的事情。

用法为:overwrite file cmd file 。< / p>

# 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

答案 4 :(得分:2)

您可以使用moreutils中的sponge

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

答案 5 :(得分:1)

也许-i是gnu sed,或者只是旧版本的sed,但无论如何。你走在正确的轨道上。第一个选项可能是最常见的选项,第三个选项是如果你想让它在任何地方工作(包括solaris机器)...... :)这些都是“标准”的方法。

答案 6 :(得分:1)

要更改多个文件(并将每个文件的备份保存为* .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)

答案 7 :(得分:0)

标准-i中没有

sed选项。

您的替代方案是您的第三种方式或perl

答案 8 :(得分:0)

很多答案,但没有一个是正确的。这是最正确和最简单的一个:

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

答案 9 :(得分:-2)

使用打开文件句柄的解决方法:

exec 3<manipulate 

阻止打开文件被截断:

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