web-dev-qa-db-ja.com

出力をsed's / c / d / 'myFileからmyFileにリダイレクトします

スクリプトで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

しかし、入力が取得されたのと同じファイルに出力をリダイレクトする標準的な方法があるかどうか疑問に思いました。

18

私は一般的に3番目の方法を使用しますが、重要な変更

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

つまり;&&に変更して、sedが成功した場合にのみ移動が行われるようにします。そうしないと、sed構文でタイプミスをするとすぐに元のファイルが失われます。

注!タイトルを読んでOPの制約がない場合 "mysedは-i"をサポートしていません:ほとんどの人にとって、sedは-iをサポートするので、これを行う最良の方法は次のとおりです。

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

37
Nathan Kidd

はい、 -iはFreeBSD/MacOSX sedでもサポートされていますが、ファイルをインプレースで編集するには引数として空の文字列が必要です。

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

コピーを移動したくない場合は、edを使用できます。

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

The Art of Unix ProgrammingのKernighanとPikeがこの問題について話し合っています。彼らの解決策は、overwriteというスクリプトを書くことです。これにより、そのようなことができるようになります。

使用法は次のとおりです。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=$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を含めると、次のように言うことができます。

replace cat dog manipulate
3
Alok Singhal

moreutils からspongeを使用できます。

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

おそらく-iはgnused、またはsedの古いバージョンですが、とにかく。あなたは正しい方向に進んでいます。最初のオプションはおそらく最も一般的なオプションであり、3番目のオプションはそれをどこでも(ソラリスマシンを含む)動作させたい場合です... :)これらはそれを行うための「標準的な」方法です。

1
falstro

複数のファイルを変更するには(そしてそれぞれのバックアップを* .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)
1
Stenemo

-iオプションは標準のsedでは使用できません。

あなたの選択肢はあなたの第三の道またはPerlです。

0
mouviciel

答えはたくさんありますが、どれも正しくありません。これが正しくて最も単純なものです:

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