ファイルを検索して置換し、ファイルを上書きしても機能せず、ファイルが空になる


604

コマンドラインからHTMLファイルに対して検索と置換を実行したいと思います。

私のコマンドは次のようになります:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html

これを実行して後でファイルを見ると、空です。それは私のファイルの内容を削除しました。

ファイルを再度復元した後、これを実行すると:

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

stdoutファイルの内容で、検索と置換が実行されています。

なんでこんなことが起こっているの?


13
Perlの代替案:perl -pi -w -e 's/STRING_TO_REPLACE/REPLACE_WITH/g;' index.html
Gjorgji Tashkovski、2011年

多くの関連するsedコマンドは、文字列を検索し、行全体置き換えるために:stackoverflow.com/questions/11245144/...
cregox

回答:


917

ときにシェルが> index.htmlコマンドラインでは、ファイル開くindex.htmlための書き込みをすべてその前の内容を拭き取り、。

これを修正するには、変更をインラインで行い、元のファイルのバックアップを作成してから変更をインプレースで行うようにする-iオプションを渡す必要がありますsed

sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

.bakがないと、Mac OSXなどの一部のプラットフォームではコマンドが失敗します。


20
truncates the file代わりに言うことはopens the fileおそらくそれをより明確にします。
ミケル

12
少なくとも私のMacでは、最初の提案は機能しません...ファイルのインプレース置換を行う場合は、拡張子を指定する必要があります。あなたは、少なくとも、長さゼロの拡張子に渡すことができますけれども:SED -i 'sの/ string_to_replaceは/ STRING_TO_REPLACE_IT / gのindex.htmlを
トムLianza

5
変数の場合sed -i.bak 's /' $ search '/' $ replace '/ g' index.html
Fatima Zohra

33
:OSX上で、同様に、-iのパラメータとして空の文字列を「」使用sed -i '' 's/blah/xx/g'
ピエール・ヒューストン

4
しかし、あなたの.bak後にはsed -i何ですか?
Patrizio Bertoni 2015

210

別の便利なパターンは次のとおりです。

sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html

これは、-iオプションを使用しなくてもほとんど同じ効果があり、さらに、何らかの理由でsedスクリプトが失敗した場合に、入力ファイルが破壊されないことを意味します。さらに、編集が成功した場合、バックアップファイルはありません。この種のイディオムはMakefileで役立ちます。

かなりの数のsedに-iオプションがありますが、すべてではありません。posix sedはそうではありません。したがって、移植性を目指している場合は、回避することをお勧めします。


9
編集が失敗した場合、バックアップファイルが配置されず、入力ファイルが破壊されない場合は+1。Macで問題なく動作しました。
マイクグレイス2014年

私のために完全に働いた。ありがとうございました!(Macの場合)
興味

1
Ubuntu Server 14.04では、sed -iがファイルのゼロ化を続けていたので、これは完全に機能しました。
Chris Giddings

2
非常にマイナーな機能強化:... && mv index.html{.tmp,}
EdwardGarson

5
@EdwardGarson確かに、それを入力している場合はおそらくこれを使用しますsh(きちんとしていることに同意します){...}。Makefile shでは、bashではなくを使用している可能性があるため、移植性(またはposixness)を目指している場合は、その構築を回避する必要があります。
Norman Grey

95
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html

これは、index.htmlファイルに対してグローバルなインプレース置換を行います。文字列を引用することで、クエリと置換での空白の問題を回避できます。


57

sedの-iオプションを使用します。例:

sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html

これは何を意味するのでしょうか?sed:-iをstdinと共に使用することはできません
シート状

2
それは空白文字が含まれている場合は、引用符であなたのパターンを囲むようにしてください-'s/STRING_TO_REPLACE/REPLACE_WITH/g'
ダグ・トンプソン

@sheetal:ファイルの-iインプレース編集を実行するため、stdin入力と組み合わせても意味がありません。
mklement0 2017

これはmacOSでは機能するかもしれませんが、Arch Linuxでは機能しません。
xdevs23

-eがないと、受け入れられた回答はMacOS、Catalinaでは機能しません。-eを指定すると機能します。
-cwhiii

18

複数のファイルを変更するには(そして各ファイルのバックアップを* .bakとして保存するには):

perl -p -i -e "s/\|/x/g" *  

ディレクトリ内のすべてのファイルを取得し|x これを「Perlパイ」と呼びます(パイとして簡単)


1
タグだけでなく、問題のステートメントを喜んで見てくれる人を見るのは良いことです。OPはsed要件として指定せず、ツールがすでに試したのでそれを使用しただけでした。
user7412956 2018

14

-iインプレース編集のオプションを使用してみてください。


6
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html

追加するリンクがある場合は、これを試してください。上記のURL(httpsで始まり、ここではwith.comで終わる)を検索し、URL文字列に置き換えます。$pub_urlここでは変数を使用しました。sここは検索を意味し、g意味し、グローバル置換意味します。

できます !


6

警告:これは危険な方法です!LinuxのI / Oバッファを乱用し、バッファリングの特定のオプションを使用して、小さなファイルを処理します。それは興味深い好奇心です。ただし、実際の状況では使用しないでください。

あなたの-iオプションに加えてsedteeユーティリティを使用することができます

からman

tee-標準入力から読み取り、標準出力とファイルに書き込みます

したがって、解決策は次のとおりです。

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html

-ここでteeは、パイプラインが確実にバッファされるように繰り返されます。次に、パイプライン内のすべてのコマンドは、動作する入力を取得するまでブロックされます。パイプライン内の各コマンドは、上流のコマンドが1バイトのバッファー(サイズはどこかで定義されている)をコマンドの入力に書き込んだときに開始されます。そのtee index.htmlため、書き込みのためにファイルを開いて空にする最後のコマンドは、上流のパイプラインが終了し、出力がパイプライン内のバッファーにある後に実行されます。

ほとんどの場合、以下は機能しません。

sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html

-ブロックせずにパイプラインの両方のコマンドを同時に実行します。(パイプラインをブロックせずにバッファによって代わりにバッファのラインでバイトラインを通過しなければならない。あなたが実行したときと同じcat | sed s/bar/GGG/。それはよりインタラクティブだとちょうど2コマンドの通常のパイプラインをバッファリングし、ブロックせずに実行ブロックせずに。長いパイプラインがバッファリングされている。)tee index.htmlの意志を書き込み用にファイルを開くと、空になります。ただし、バッファリングを常にオンにすると、2番目のバージョンも機能します。


3
teeの出力ファイルもすぐに開かれ、コマンド全体に対して空のindex.htmlが生成されます。
sjngm

3
これにより、パイプラインバッファー(通常は64KB)より大きい入力ファイルが破損します。(@sjngm:のようにファイルがすぐに切り捨てられるわけではありません>が、要点は、データが失われる可能性が高い壊れたソリューションであることです)。
mklement0 2017

4

コマンドの問題

sed 'code' file > file

これは、filesedが実際に処理する前に、シェルによって切り捨てられることです。その結果、空のファイルが作成されます。

-i他の回答が示唆するように、これを行うsedの方法は、を使用してその場で編集することです。ただし、これが常に望ましいとは限りません。-i一時ファイルが作成され、元のファイルを置き換えるために使用されます。元のファイルがリンクだった場合、これは問題になります(リンクは通常のファイルに置き換えられます)。リンクを保持する必要がある場合は、次のように一時変数を使用して、sedの出力をファイルに書き戻す前に保存できます。

tmp=$(sed 'code' file); echo -n "$tmp" > file

さらに良いことprintfに、一部のシェル(ダッシュなど)と同様に処理される可能性が高いechoので、代わりに使用echoします。\\\

tmp=$(sed 'code' file); printf "%s" "$tmp" > file

1
リンクを保持するための+1。また、一時ファイルで動作します:sed 'code' file > file.tmp; cat file.tmp > file; rm file.tmp
dashohoxha

3

そしてed答え:

printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html

codaddictが答えたことを繰り返すために、シェルは最初にリダイレクションを処理し、「input.html」ファイルを一掃し、次にシェルは「sed」コマンドを呼び出して、現在空のファイルを渡します。


2
簡単な質問、なぜ人々edsed答えの「バージョン」を与え続けるのですか?それはより速く機能しますか?
cregox 2013

6
一部sedのは-iインプレース編集を実装していません。edユビキタスであり、編集内容を元のファイルに保存できます。さらに、キットに多くのツールを含めることは常に良いことです。
グレン・ジャックマン2013

うんいいね。ですから、パフォーマンスに関しては、私が想定しているものと同じです。ありがとう!
cregox 2013

2

VimはExモードで使用できます。

ex -sc '%s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g|x' index.html
  1. % すべての行を選択

  2. x 保存して閉じます


0

行の範囲を定義できるオプションを探していて、答えを見つけました。たとえば、36行目から57行目でhost1をhost2に変更します。

sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt

大文字と小文字を区別するために、giオプションも使用できます。

sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt

0

上記の正解をすべて尊重して、ファイルを破損せずに最初からやり直す必要があるように、そのようなスクリプトを「ドライラン」することは常に良い考えです。

たとえば、次のように、ファイルに書き込む代わりに、スクリプトに出力をコマンドラインに書き出すだけです。

sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html

または

less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g 

これにより、ファイルを切り詰めることなく、コマンドの出力を確認できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.