既存のファイルを直接変更し、「baz」を含む行に対してのみ「foo」を「bar」に置き換えます。

既存のファイルを直接変更し、「baz」を含む行に対してのみ「foo」を「bar」に置き換えます。

以下の food.txt ファイルがあります。

mangoes|foo|faa  
oranges|foo|faa  
chocolates|foo|baz  

交換しようとしています。金持ちそしてバー条件が満たされたらbaz。 (ここではregex b * zを使うつもりです)
現在、以下のsedコマンドを使用していますが、既存のファイルを直接変更するわけではありません。また、正規表現(b*z)も使用できません。

sed '/baz/s/foo/bar/g' food.txt

既存のファイルを直接変更するには、「sed」以外に他の方法を提案してください。

PS:試してみましたが、sed -ised以外のコマンドを使用したいと思います。
mobaxterm(OS - Windows)を使用しています。

答え1

sedこの状況で使用するのに問題はないと思います。これは仕事に適したツールです。

あなたのコマンドは(与えられたデータに対して)うまく機能します。

$ sed '/baz/s/foo/bar/g' food.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

正規表現を使用して、|b行の終わり(行のどこにもない)で始まり、終わるすべての文字列を一致させます。zbaz

$ sed '/|b.*z$/s/foo/bar/g' food.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

ファイルを変更するには(GNUを使用sed):

$ sed -i '/|b.*z$/s/foo/bar/g' food.txt

または(すべてのsed実装):

$ sed '/|b.*z$/s/foo/bar/g' food.txt >tmpfile && mv tmpfile food.txt

以下も使用できますawk

$ awk 'BEGIN { OFS=FS="|" } $3 == "baz" { $2 = "bar" }; 1' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

^b.*z$または、3番目のフィールドで一致します。

$ awk 'BEGIN { OFS=FS="|" } $3 ~ /^b.*z$/ { $2 = "bar" }; 1' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

...またはミラーmlr)、ここで入力は、フィールド区切り文字として使用されるヘッダーなしのCSVファイルとして読み込まれます|

$ mlr --csv -N --fs pipe put '$3 == "baz" { $2 = "bar" }' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

または、

$ mlr --csv -N --fs pipe put '$3 =~ "^b.*z$" { $2 = "bar" }' file
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

awkあるいは、Millerを使用すると、分離されたフィールドに対してパターンをより簡単かつ安全に一致させることができるという利点があります。 Millerのもう一つの利点は、CSVの引用規則を理解することです。

答え2

awk次のように使用しますgsub()

awk '/baz$/ {gsub("foo", "bar")};1' food.txt
  • /baz$/必要に応じて、正規表現パターンを代わりに使用して一致させることができます。

  • パターンが一致したら、gsub()必要な文字列を置き換えます。


内部編集のために、最新バージョンのGNU awk(> = 4.1.0)には内部修正オプションがあります。

awk -i inplace '/baz$/ {gsub("foo", "bar")};1' food.txt

spongeそれ以外の場合は、GNUを使用するかmoreutils一時ファイルを使用できます。

awk '/baz$/ {gsub("foo", "bar")};1' food.txt >temp_food.txt && \
      mv temp_food.txt food.txt

例:

$ cat file.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|foo|baz

$ awk '/baz$/ {gsub("foo", "bar")};1' file.txt
mangoes|foo|faa
oranges|foo|faa
chocolates|bar|baz

答え3

sed -i必要なものを正確に実行するのを使用したくない理由はわかりませんが、代替案は次のとおりですperl

$ perl -pe 's/foo/bar/g if /b*z/' food.txt 
mangoes|foo|faa  
oranges|foo|faa  
chocolates|bar|baz

これは、-pe「スクリプトを適用した後、入力ファイルの各行を印刷します。

-i以下を使用して、その場所でファイルを編集できます。

perl -i -pe 's/foo/bar/g if /b*z/' food.txt 

また、正規表現はb*z「0以上に一致し、b後にaが続くことを意味します。andをz省略して一致し、一致のみするため、ここで機能します。b*zつまり、anyは0の例の後にaになるため、どんなものとも一致します。 I 使いたいのは b.*z(ab の後に 0 個以上の文字が来て az が来ます)と考えてください。barbazzzbz

perl -i -pe 's/foo/bar/g if /b.*z/' food.txt 

答え4

自動テキスト編集のための実際に最適なツールは次のとおりです。ex

直接電話することも可能でしょうがex、探してみるとMobaXtermから電話する必要がありますvim -e

自動編集を行う最良の方法はMobaXtermから(他の* nixシステムでも機能します)は次のとおりです。

printf '%s\n' 'g/b.*z/s/foo/bar/g' x | vim -es food.txt

POSIXと完全に互換性があるようにするには、次のように変更してください。

printf '%s\n' 'g/b.*z/s/foo/bar/g' x | ex -s food.txt

ただし、このexコマンドを呼び出すと、MobaXtermで正しく機能しなくなる可能性があります(私がインストールした場合は動作しませんでした)。そのバージョンが失敗した場合は、vim -esこのバージョンのコマンドを試してください。ex

関連情報