手動でしなくても、単一のsedコマンドでファイルを編集できるかどうかを調べようとしています編集したコンテンツを新しいファイルにストリーミングしてから、新しいファイルの名前を元のファイル名に変更します。私は-i
オプションを試しましたが、私のSolarisシステムは-i
は違法なオプションであると言いました。別の方法はありますか?
-i
オプション は編集されたコンテンツを新しいファイルにストリーミングし、それから舞台裏で名前を変更します。
例:
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
そして
sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
onmacOS。
sed
がその場でファイルを編集する能力を持っていないシステムでは、私はもっと良い解決策がPerl
を使うことだと思います:
Perl -pi -e 's/foo/bar/g' file.txt
これは一時ファイルを作成しますが、元のファイルを置き換えます。空の場所の接尾辞/拡張子が指定されているためです。
OS Xでは、このコマンドを実行すると、「無効なコマンドコード」などの奇妙なエラーやその他の奇妙なエラーが発生する可能性があります。この問題を解決するには
sed -i '' -e "s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g" <file>
これは、OSXバージョンのsed
では、-i
オプションがextension
引数を想定しているため、実際にはコマンドがextension
引数として解析され、ファイルパスがコマンドコードとして解釈されるためです。出典: https://stackoverflow.com/a/19457213
以下は私のMacでは問題なく動作します。
sed -i.bak 's/foo/bar/g' sample
サンプルファイルでは、fooをbarに置き換えています。元のファイルのバックアップはsample.bakに保存されます
バックアップなしでインライン編集するには、次のコマンドを使用します。
sed -i'' 's/foo/bar/g' sample
注意すべきことは、sedの唯一の目的はsed
がそれ自身でファイルを書くことができないということです( "stdin"、 "stdout"、 "stderr"、その他の ">&n
"バッファ、ソケットなどのパイプライン)。これを念頭に置いて、別のコマンドtee
を使用して出力をファイルに書き戻すことができます。もう1つの選択肢は、コンテンツをdiff
にパイプ処理してパッチを作成することです。
ティーメソッド
sed '/regex/' <file> | tee <file>
パッチ方式
sed '/regex/' <file> | diff -p <file> /dev/stdin | patch
更新:
また、patchはファイルを差分出力の1行目から変更するようにします。
これはdiffからの出力の最初の行にあるので、patchはどのファイルにアクセスするかを知る必要はありません。
$ echo foobar | tee fubar
$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin
*** fubar 2014-03-15 18:06:09.000000000 -0500
--- /dev/stdin 2014-03-15 18:06:41.000000000 -0500
***************
*** 1 ****
! foobar
--- 1 ----
! fubar
$ sed 's/oo/u/' fubar | diff -p fubar /dev/stdin | patch
patching file fubar
あなたが望むことをsed
ですることは不可能です。その場でファイルを編集するための-i
オプションをサポートするsed
のバージョンでさえ、あなたが明示的にあなたが望まないと述べたことをまさに行います:それらは一時ファイルに書いてからファイルの名前を変更します。しかし、おそらくed
を使うことができます。たとえば、ファイルfile.txt
内のすべてのfoo
をbar
に変更するには、次のようにします。
echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt
構文はsed
に似ていますが、まったく同じというわけではありません。
しかし、おそらく、名前を変更した一時ファイルを使用したくない理由を検討する必要があります。あなたがsed
をサポートする-i
を持っていなくても、あなたのために仕事をするスクリプトを簡単に書くことができます。 sed -i 's/foo/bar/g' file
の代わりに、inline file sed 's/foo/bar/g'
をすることができます。そのようなスクリプトは書くのが簡単です。例えば:
#!/bin/sh -e
IN=$1
shift
trap 'rm -f $tmp' 0
tmp=$( mktemp )
<$IN "$@" >$tmp && cat $tmp > $IN # preserve hard links
ほとんどの用途に適しているはずです。
sed はインプレース編集をサポートします。 man sed
から:
-i[SUFFIX], --in-place[=SUFFIX]
edit files in place (makes backup if extension supplied)
例:
テキスト付きのファイルhello.txt
があるとしましょう。
hello world!
古いファイルのバックアップを保存したい場合は、次のようにします。
sed -i.bak 's/hello/bonjour' hello.txt
hello.txt
という内容のファイルが2つあります。
bonjour world!
古いコンテンツのhello.txt.bak
。
コピーを残したくない場合は、単にextensionパラメータを渡さないでください。
あなたはviを使うことができます
vi -c '%s/foo/bar/g' my.txt -c 'wq'
リダイレクト演算子<>
を使ってファイルを開いて読み書きすることもできます。
sed 's/foo/bar/g' file 1<> file
ライブで見てください。
$ cat file
hello
i am here # see "here"
$ sed 's/here/away/' file 1<> file # Run the `sed` command
$ cat file
hello
i am away # this line is changed now
bashリファレンスマニュアルから→3.6.10読み書き用のファイルディスクリプタを開く :
リダイレクト演算子
[n]<>Word
ファイル記述子n、またはnが指定されていない場合はファイル記述子0の読み取りと書き込みの両方で、名前がWordの展開であるファイルを開きます。ファイルが存在しない場合は作成されます。
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
出力は元のファイルの内容を上書きするように戻され、特別なバージョンのsedが不要になるため、すべてのハードリンクを保存する必要があります。
どのシェルを使用しているかは指定しませんでしたが、zshではこれを実現するために=( )
構文を使用できました。次の行に沿った何か
cp =(sed ... file; sync) file
=( )
は>( )
と似ていますが、cp
が終了すると自動的に削除される一時ファイルを作成します。
非常に良い例です。多くのファイルをその場で編集するという課題があり、-iオプションがfindコマンド内でそれを使用する唯一の妥当なソリューションであるようです。ここで、各ファイルの最初の行の前に「バージョン:」を追加するスクリプト:
find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;
MoneypennyがSkyfallで言ったように、「時には古い方法が最善です。」 Kincadeは後で似たようなことを言った。
$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}
代わりに幸せな編集。ファイルを書き込むために '\ nw\n'を追加しました。遅延応答要求に対する謝罪.