web-dev-qa-db-ja.com

その場でsed編集ファイル

手動でしなくても、単一のsedコマンドでファイルを編集できるかどうかを調べようとしています編集したコンテンツを新しいファイルにストリーミングしてから、新しいファイルの名前を元のファイル名に変更します。私は-iオプションを試しましたが、私のSolarisシステムは-iは違法なオプションであると言いました。別の方法はありますか?

238
amphibient

-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

356
choroba

sedがその場でファイルを編集する能力を持っていないシステムでは、私はもっと良い解決策がPerlを使うことだと思います:

Perl -pi -e 's/foo/bar/g' file.txt

これは一時ファイルを作成しますが、元のファイルを置き換えます。空の場所の接尾辞/拡張子が指定されているためです。

68
Steve

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

46
diadyne

以下は私のMacでは問題なく動作します。

sed -i.bak 's/foo/bar/g' sample

サンプルファイルでは、fooをbarに置き換えています。元のファイルのバックアップはsample.bakに保存されます

バックアップなしでインライン編集するには、次のコマンドを使用します。

sed -i'' 's/foo/bar/g' sample
21
minhas23

注意すべきことは、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
12
Dwight Spencer

あなたが望むことをsedですることは不可能です。その場でファイルを編集するための-iオプションをサポートするsedのバージョンでさえ、あなたが明示的にあなたが望まないと述べたことをまさに行います:それらは一時ファイルに書いてからファイルの名前を変更します。しかし、おそらくedを使うことができます。たとえば、ファイルfile.txt内のすべてのfoobarに変更するには、次のようにします。

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

ほとんどの用途に適しているはずです。

10
William Pursell

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パラメータを渡さないでください。

7
Sergio A.

あなたはviを使うことができます

vi -c '%s/foo/bar/g' my.txt -c 'wq'
7
mench

同数の文字を置き換えている場合、 ファイルの「インプレース」編集をよく読んだ後 ...

リダイレクト演算子<>を使ってファイルを開いて読み書きすることもできます。

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の展開であるファイルを開きます。ファイルが存在しない場合は作成されます。

3
fedorqui
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt

出力は元のファイルの内容を上書きするように戻され、特別なバージョンのsedが不要になるため、すべてのハードリンクを保存する必要があります。

3
JJM

どのシェルを使用しているかは指定しませんでしたが、zshではこれを実現するために=( )構文を使用できました。次の行に沿った何か

cp =(sed ... file; sync) file

=( )>( )と似ていますが、cpが終了すると自動的に削除される一時ファイルを作成します。

1
Thor

非常に良い例です。多くのファイルをその場で編集するという課題があり、-iオプションがfindコマンド内でそれを使用する唯一の妥当なソリューションであるようです。ここで、各ファイルの最初の行の前に「バージョン:」を追加するスクリプト:

find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;
1
Robert

MoneypennyがSkyfallで言ったように、「時には古い方法が最善です。」 Kincadeは後で似たようなことを言った。

$ printf ',s/false/true/g\nw\n' | ed {YourFileHere}

代わりに幸せな編集。ファイルを書き込むために '\ nw\n'を追加しました。遅延応答要求に対する謝罪.

0
jlettvin