重定向 sed 's/c/d/' 的输出我的文件到我的文件

发布于 2024-08-27 16:20:57 字数 424 浏览 8 评论 0原文

我在脚本中使用 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

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

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 -i 's/cat/dog/' manipulate
sed: illegal option -- i

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

女皇必胜 2024-09-03 16:20:57

我通常使用第三种方法,但有一个重要更改

sed 's/cat/dog/'操作> tmp && mv tmp Operate

即,将 ; 更改为 &&,因此只有在 sed 成功时才会发生移动;否则,一旦您在 sed 语法中输入错误,您就会丢失原始文件。

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

sed -i 's/cat/dog/' Operate

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

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.

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:

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

掀纱窥君容 2024-09-03 16:20:57

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

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

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

sed -i "" 's/old/new/g' file   # FreeBSD sed
温暖的光 2024-09-03 16:20:57

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

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

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

ed file.txt <<EOF
%s/cat/dog/
wq
EOF
美煞众生 2024-09-03 16:20:57

Kernighan 和 Pike 在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

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

The usage is: 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

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

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

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

# 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

Having replace in your $PATH too will allow you to say:

replace cat dog manipulate
全部不再 2024-09-03 16:20:57

您可以使用 moreutils 中的 sponge

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

You can use sponge from the moreutils.

sed "s/cat/dog/" manipulate | sponge manipulate
你的呼吸 2024-09-03 16:20:57

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

Perhaps -i is 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.

水晶透心 2024-09-03 16:20:57

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

To change multiple files (and saving a backup of each as *.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)
人│生佛魔见 2024-09-03 16:20:57

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

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

-i option is not available in standard sed.

Your alternatives are your third way or perl.

偏爱自由 2024-09-03 16:20:57

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

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

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
$ 
怪我入戏太深 2024-09-03 16:20:57

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

exec 3<manipulate 

防止打开的文件被截断:

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

Workaround using open file handles:

exec 3<manipulate 

Prevent open file from being truncated:

rm manipulate
sed 's/cat/dog/' <&3 > manipulate
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文