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

2019-01-17 20:59发布

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.

10条回答
Anthone
2楼-- · 2019-01-17 21:33

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
查看更多
不美不萌又怎样
3楼-- · 2019-01-17 21:38

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

查看更多
一夜七次
4楼-- · 2019-01-17 21:40

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
查看更多
在下西门庆
5楼-- · 2019-01-17 21:43

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.

查看更多
我欲成王,谁敢阻挡
6楼-- · 2019-01-17 21:47

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
$ 
查看更多
太酷不给撩
7楼-- · 2019-01-17 21:49

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

ed file.txt <<EOF
%s/cat/dog/
wq
EOF
查看更多
登录 后发表回答