スクリプトで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
しかし、入力が取得されたのと同じファイルに出力をリダイレクトする標準的な方法があるかどうか疑問に思いました。
私は一般的に3番目の方法を使用しますが、重要な変更:
$ sed 's/cat/dog/' manipulate > tmp && mv tmp manipulate
つまり;
を&&
に変更して、sedが成功した場合にのみ移動が行われるようにします。そうしないと、sed構文でタイプミスをするとすぐに元のファイルが失われます。
注!タイトルを読んでOPの制約がない場合 "mysedは-i
"をサポートしていません:ほとんどの人にとって、sedは-i
をサポートするので、これを行う最良の方法は次のとおりです。
$ sed -i 's/cat/dog/' manipulate
はい、 -i
はFreeBSD/MacOSX sed
でもサポートされていますが、ファイルをインプレースで編集するには引数として空の文字列が必要です。
sed -i "" 's/old/new/g' file # FreeBSD sed
コピーを移動したくない場合は、edを使用できます。
ed file.txt <<EOF
%s/cat/dog/
wq
EOF
The Art of Unix ProgrammingのKernighanとPikeがこの問題について話し合っています。彼らの解決策は、overwrite
というスクリプトを書くことです。これにより、そのようなことができるようになります。
使用法は次のとおりです。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
上記のスクリプトを$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
moreutils からsponge
を使用できます。
sed "s/cat/dog/" manipulate | sponge manipulate
おそらく-i
はgnused、またはsedの古いバージョンですが、とにかく。あなたは正しい方向に進んでいます。最初のオプションはおそらく最も一般的なオプションであり、3番目のオプションはそれをどこでも(ソラリスマシンを含む)動作させたい場合です... :)これらはそれを行うための「標準的な」方法です。
複数のファイルを変更するには(そしてそれぞれのバックアップを* .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)
-i
オプションは標準のsed
では使用できません。
あなたの選択肢はあなたの第三の道またはPerl
です。
答えはたくさんありますが、どれも正しくありません。これが正しくて最も単純なものです:
$ echo "111 222 333" > file.txt
$ sed -i -s s/222/444/ file.txt
$ cat file.txt
111 444 333
$