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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2585438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 19:09:13  来源:igfitidea点击:

Redirect output from sed 's/c/d/' myFile to myFile

bashsedsolarisredirect

提问by sixtyfootersdude

I am using sed in a script to do a replace and I want to have the replaced file overwrite the file. Normally I think that you would use this:

我在脚本中使用 sed 进行替换,我想让替换的文件覆盖该文件。通常我认为你会使用这个:

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

However as you can see my sed does not have that command.

但是,正如您所看到的,我的 sed 没有该命令。

I tried this:

我试过这个:

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

But this just turns manipulate into an empty file (makes sense).

但这只是将操纵变成了一个空文件(有道理)。

This works:

这有效:

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

But I was wondering if there was a standard way to redirect output into the same file that input was taken from.

但我想知道是否有一种标准的方法可以将输出重定向到与输入相同的文件中。

回答by Nathan Kidd

I commonly use the 3rd way, but with an important change:

我通常使用第三种方式,但有一个重要的变化

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

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

I.e. change ;to &&so the move only happens if sed is successful; otherwise you'll lose your original file as soon as you make a typo in your sed syntax.

即更改;&&因此移动仅在 sed 成功时发生;否则,只要您在 sed 语法中打错字,您就会丢失原始文件。

Note!For those reading the title and missing the OP's constraint "my sed doesn't support -i": For most people, sed will support -i, so the best way to do this is:

笔记!对于那些阅读标题并错过 OP 约束“我的 sed 不支持-i”的人:对于大多数人来说, sed 将支持-i,因此最好的方法是:

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

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

回答by gatt

Yes, -iis also supported in FreeBSD/MacOSX sed, but needs the empty string as an argument to edit a file in-place.

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

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

回答by amertune

If you don't want to move copies around, you could use ed:

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

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

回答by Alok Singhal

Kernighan and Pike in The Art of Unix Programmingdiscuss this issue. Their solution is to write a script called overwrite, which allows one to do such things.

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

The usage is: overwritefilecmdfile.

用法是:。overwritefilecmdfile

# 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=; 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:  failed, $file unchanged" 1>&2
       exit 1
fi
rm -f $new $old

Once you have the above script in your $PATH, you can do:

在您的 中有上述脚本后$PATH,您可以执行以下操作:

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

To make your life easier, you can use replacescript from the same book:

为了让您的生活更轻松,您可以使用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=""; right=""; shift; shift

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

Having replacein your $PATHtoo will allow you to say:

拥有replace你的$PATH太将让你说:

replace cat dog manipulate

回答by nh2

You can use spongefrom the moreutils.

您可以spongemoreutils使用。

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

回答by Stenemo

To change multiple files (and saving a backup of each as *.bak):

要更改多个文件(并将每个文件的备份保存为 *.bak):

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

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)

回答by falstro

Perhaps -iis gnu sed, or just an old version of sed, but anyways. You're on the right track. The first option is probably the most common one, the third option is if you want it to work everywhere (including solaris machines)... :) These are the 'standard' ways of doing it.

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

回答by mouviciel

-ioption is not available in standard sed.

-i选项在标准中不可用sed

Your alternatives are your third way or perl.

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

回答by Vladimir Prudnikov

A lot of answers, but none of them is correct. Here is the correct and simplest one:

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

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

回答by Jürgen H?tzel

Workaround using open file handles:

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

exec 3<manipulate 

Prevent open file from being truncated:

防止打开的文件被截断:

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