Grepで正しい行を見つけ、sedで内容を変更してから、元のファイルに戻しますか?


9

ファイルの特定の行の1つの単語を変更しようとしていますが、すべてを一緒に接続するのに問題があります。

基本的に、ファイルの1行に「firmware_revision」というキーワードがあり、この行(およびこの行のみ)に「test」という単語を「production」という単語に置き換えたいと思います。

だから私はこれを行うことができます:

grep 'firmware_revision' myfile.py | sed 's/test/production'

これにより、必要な行が選択され、置換が実行されますが、この新しい行を元のファイルに入れて古い行を置き換える方法がわかりません。ファイルにリダイレクトすることはできないので、どうすればよいですか?

一時grepファイルを使用していても、を使用して必要な行だけを取得すると、ファイル内の他のすべてのデータが失われるため、すべてを一時ファイルにリダイレクトして元のファイルを一時ファイルに置き換えることはできなくなります。

編集-誰かが詳細情報を求めました

このような行でいっぱいのファイルがあるとしましょう

[
  ('key_name1', str, 'value1', 'Description'),
  ('key_name2', str, 'value2', 'Description'),
  ('key_name3', str, 'value3', 'Description'),
  ('firmware_revision', str, 'my-firmware-name-test', 'Firmware revision name')
]

ここで、「firmware_revision」を含む行を検索し、その行の「test」という単語のすべてのインスタンスを「production」に変更するスクリプト(理想的には1行)を記述したいと思います。「テスト」という単語がそのファイルの他の場所にある可能性があり、それらを変更したくありません。明確にするために、上の行を

('firmware_revision', str, 'my-firmware-name-production', 'Firmware revision name')

どうすればよいですか?


5
sedは非常に強力であり、両方の機能(grepおよび置換)を実行できますが、ラインがどのように見えるかについての詳細情報が必要になります。
2016

元の投稿にさらに情報を追加します
John Allard

7
試してみてくださいsed -i.bak '/firmware_revision/ s/test/production/' myfile.py
John1024

1
ああ、完璧に機能しました!構文を説明できますか?
ジョンアラード

@JohnAllardとても良い。説明付きで回答を追加しました。
John1024

回答:


22

試してください:

sed -i.bak '/firmware_revision/ s/test/production/' myfile.py

ここで/firmware_revision/は、条件として機能します。これは、正規表現に一致する行に当てはまり、firmware_revision他の行にはfalseです。条件が真の場合、次のコマンドが実行されます。この場合、そのコマンドは、最初に出現代わる代替コマンドであるtestとしますproduction

つまり、コマンドs/test/production/はregexに一致する行でのみ実行されfirmware_revisionます。他のすべてのラインは変更されずに通過します。

デフォルトでは、sedは出力を標準出力に送信します。ただし、ファイルを適切に変更したいと考えていました。そこで、-iオプションを追加しました。特に、拡張子が-i.bak付いたバックアップコピーが保存された状態でファイルが変更されます.bak

コマンドが機能し、危険な状況でバックアップを作成したくない場合は、GNU sed(Linux)を使用します。

sed -i '/firmware_revision/ s/test/production/' myfile.py

対照的に、BSD(OSX)では、-iオプションに引数が必要です。バックアップを保持したくない場合は、空の引数を指定してください。したがって、以下を使用します。

sed -i '' '/firmware_revision/ s/test/production/' myfile.py

編集する

質問の編集で、OPは、行に出現するすべてのtestをに置き換えるように求めproductionます。その場合、(その行の)グローバルg置換の代替コマンドにオプションを追加します。

sed -i.bak '/firmware_revision/ s/test/production/g' myfile.py

5
完全を期すために、その-i.bak部分についても説明することをお勧めします。
スティーブンハリス

5
@StephenHarrisいいね。-i追加の説明。
John1024

私はあなたがたぶん星に到達することがsedできると思います、できることすべてを説明する本の上に立つだけ
KlaymenDK

John1024 @ BSDない人々のために、あなたは最初の理由から追加することができ ''た後に-i
Hastur

3
OPは、その行の「test」という単語のすべてのインスタンスを「production」変更したいと考えていました。この場合、sedコマンドに/ gを追加することが重要です。sed -i '/firmware_revision/ s/test/production/g' myfile.pyそれ以外の場合は、最初のインスタンスのみが変更されます。
knub 2016

4

sedオプションをサポートしていない旧式の古いマシンでは-i

TF=$( mktemp -t "${0##*/}"_$$_XXXXXXXX ) && \
trap 'rm -f "$TF"' EXIT HUP INT QUIT TERM && \
sed '/firmware_revision/ s/test/production/' myfile.py >"$TF" && \
mv -f "$TF" myfile.py

1
これらの古いマシンedでは、1行で簡単に使用および実行できますprintf %s\\n g/firmware_revision/s/test/production/g w q | ed -s myfile.py
。– don_crissti

1
@don_crissti非常にそうですが、ed(1)の使用を示す口実はありませんmktemp(1)
佐藤桂2016

一時ファイルを使用している場合は、元のファイルのinodeとpermsをそのまま保持することもできますed。の代わりにmv -f "$TF" myfile.pl、を使用してくださいcat "$TF" > myfile.pl && rm -f "$TF"。ところで、(の$tf代わりに$TF)小文字の変数名を使用するのは良い習慣です。bashの組み込み変数(おそらく他のボーンシェルも)と競合しないことが保証されています。
cas

@cas Re::cat "$TF" > myfile.plこれを試してくださいtouch a b; chmod 0444 a; cat b >a(BTW、sed -iその場合も機能しません)。ユーザーがそれに対処できるようにしてください。Re::rm -f "$TF"必要ありませんtrap ... EXIT。を参照してください。Re:$tf代わりに$TF:多分; それはスタイルの問題です。
桂佐藤2016

これは、UNIXファイルのアクセス許可の正常な動作です。私のポイントは、新しいファイルを作成し、元のファイルにmv-ingすると、そのファイル名の新しいiノードが1になる(ハードリンクが壊れる)ことです。2.電流umask が元のパーマと異なる場合は、パーマを変更する可能性があります。大文字の変数については、それはスタイルの問題だけではありません。大文字のPATH、RANDOM、SHELL、または独自の変数に何でも使用するという間違いを犯した多くの人々は、難しい方法を見つけました。(そして、はい、私はしばしば大文字の変数を自分で使用します。私はそれが間違っていることを知っています、私は習慣を壊そうとしています)。
cas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.