編集したコンテンツを手動で新しいファイルにストリーミングしてから、新しいファイルの名前を元のファイル名に変更せずに、1つのsedコマンドでファイルを編集できるかどうかを調べようとしています。このオプションを試しました-i
が、Solarisシステムはそれ-i
が不正なオプションであると言っていました。別の方法はありますか?
15 に答える
この-i
オプションは、編集されたコンテンツを新しいファイルにストリーミングし、バックグラウンドで名前を変更します。
例:
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
macOS では次のものが必要です。
sed -i '' 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' filename
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
アップデート:
また、パッチは差分出力の 1 行目から変更するファイルを取得することに注意してください。
これは diff からの出力の最初の行にあるため、パッチはアクセスするファイルを知る必要はありません。
$ 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
、一時ファイルに書き込んでからファイルの名前を変更します。
または、を使用することもできますed
。たとえば、ファイル内のfoo
toのすべての出現箇所を変更するには、次のようにします。bar
file.txt
echo ',s/foo/bar/g; w' | tr \; '\012' | ed -s file.txt
構文はに似てsed
いますが、まったく同じではありません。
-i
サポートがない場合でもsed
、作業を行うためのスクリプトを簡単に作成できます。の代わりにsed -i 's/foo/bar/g' file
、を行うことができますinline file sed 's/foo/bar/g'
。このようなスクリプトを書くのは簡単です。例えば:
#!/bin/sh
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
最終的に次の 2 つのファイルが作成されます。hello.txt
内容は次のとおりです。
bonjour world!
しかもhello.txt.bak
古い内容で。
コピーを保持したくない場合は、拡張パラメーターを渡さないでください。
同じ量の文字を置き換える場合、ファイルの「インプレース」編集を注意深く読んだ後...
また、リダイレクト演算子を使用し<>
てファイルを開いて読み書きすることもできます。
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
word の展開である名前のファイルが、ファイル記述子 n で、または n が指定されていない場合はファイル記述子 0 で、読み取りと書き込みの両方のために開かれます。ファイルが存在しない場合は、作成されます。
mv file.txt file.tmp && sed 's/foo/bar/g' < file.tmp > file.txt
出力は元のファイルの内容を上書きするように指示され、特別なバージョンの sed が不要になるため、すべてのハードリンクを保持する必要があります。
使用しているシェルを指定しませんでしたが、zsh を使用すると、=( )
構造を使用してこれを実現できます。次のようなもの:
cp =(sed ... file; sync) file
=( )
に似て>( )
いますが、終了時に自動的に削除される一時ファイルを作成しcp
ます。
非常に良い例です。多くのファイルをその場で編集するという課題がありました. -i オプションは、 find コマンド内でそれを使用する唯一の合理的な解決策のようです. 各ファイルの最初の行の前に「version:」を追加するスクリプトは次のとおりです。
find . -name pkg.json -print -exec sed -i '.bak' '1 s/^/version /' {} \;