テキストファイルでの置換**正規表現なし**


68

テキストファイル内のテキストを置換する必要があります。通常、私は次のようなことをします

sed -i 's/text/replacement/g' path/to/the/file

問題は、両方のことであるtextとは、replacementその上のダッシュ、スラッシュ、blackslashes、引用符とを含む複雑な文字列です。text物の中の必要な文字をすべてエスケープすると、すぐに読めなくなります。一方、正規表現の力は必要ありません。テキストを文字通りに置き換えるだけです。

いくつかのbashコマンドで正規表現を使用せずにテキスト置換を行う方法はありますか?

これを行うスクリプトを作成するのは簡単ですが、既に何かが存在するはずです。


bashを使用して行う必要がありますか?単純化した解決策は、Wordで開いてfind and replace all
-Akash

17
@akash bash常にMicrosoft Wordに同梱されているシステムですか?;) いや、冗談よ。OPは、リモートマシン上で、またはファイルのバッチに対してこれを実行する場合があります。
-slhck

@slhck :)まあ、私はgeditのは、同様のオプション持っている必要がありますね
Akashさん

オプションは、を渡す前に何らかの方法ですべてを正しくエスケープすることですsed。これはおそらく、すべてのスイッチとプラットフォームの違いを考慮すると無駄な努力です。
-l0b0

回答:


6

正規表現のパワーが必要ない場合は、使用しないでください。それは結構です。
しかし、これは実際には正規表現ではありません。

sed 's|literal_pattern|replacement_string|g'

だから、もし/あなたの問題なら|、前者をエスケープする必要はありません。

ps:コメントについては、Sed検索パターンの文字列をエスケープする Stackoverflowの回答もご覧ください。


更新:あなたは罰金を使用している場合はPerlをして、それを試す\Q\E、このように、
perl -pe 's|\Qliteral_pattern\E|replacement_string|g'
RedGrittyBrickここにもコメントに強いPerlの構文と同様のトリックを示唆しています


ありがとう、私は/と|の違いを知らなかった
アンドレア

64
私はこの答えは...との唯一の違いに有用であるか分からないs|||s///区切り文字の文字が異なっているので、ということである1つの文字をエスケープする必要はありません。同様に行うことができますs###。ここでの本当の問題は、OPがコンテンツのエスケープを心配する必要がないことですliteral_pattern(これはまったくリテラルではなく、正規表現として解釈されます)。
ベンジュ

15
これは、他の特殊文字の解釈を回避しません。1234.*aaaソリューションで検索した場合、意図したものよりもはるかに一致します1234\.\*aaa
マッテオ

20
この答えは受け入れられませ
スティーブンルー

2
これはポイントを完全に見逃しています。一致させるテキストには、あらゆる奇妙さが含まれる可能性があります。私の場合、それはランダムなパスワードです。あなたはそれらがどうなるか知っています
クリスチャンボンジョルノ

13
export FIND='find this'
export REPLACE='replace with this'
ruby -p -i -e "gsub(ENV['FIND'], ENV['REPLACE'])" path/to/file

これは、ここでの唯一の100%安全なソリューションです。

  • それは正規表現ではなく静的な置換であり、何もエスケープする必要はありません(したがって、を使用するよりも優れていますsed
  • 文字列に}char が含まれていても壊れません(したがって、提出されたPerlソリューションよりも優れています)
  • ENV['FIND']が使用されているためではなく、どの文字でも破損しません$FIND$FINDしたり、テキストはRubyのコードにインライン化あなたの文字列がエスケープされていないが含まれている場合、あなたは構文エラーを打つ可能性が'

export FIND='find this; export REPLACE='replace with this';そのため、bashスクリプトで使用する必要がENV['FIND']ありENV['replace']、期待される値が得られました。ファイル内の非常に長い暗号化された文字列を置き換えていました。これは単なるチケットでした。
-DMfll

これは信頼できる答えであり、ルビーはどこにでもあるからです。この答えに基づいて、このシェルスクリプトを使用します
-loevborg

FINDに複数の行が含まれている場合、残念ながら機能しません。
adrelanos

FINDで複数の行を処理することを妨げるものはありません。二重引用符で囲まれた\ nを使用します。
Nowaker

7

replaceコマンドは、これを行います。

https://linux.die.net/man/1/replace

場所の変更:

replace text replacement -- path/to/the/file

標準出力するには:

replace text replacement < path/to/the/file

例:

$ replace '.*' '[^a-z ]{1,3}' <<EOF
> r1: /.*/g
> r2: /.*/gi
> EOF
r1: /[^a-z ]{1,3}/g
r2: /[^a-z ]{1,3}/gi

このreplaceコマンドは、MySQLまたはMariaDBに付属しています。


3
置き換えTHT考慮して廃止されており、将来的にはdisponibleではないかもしれない
ロヘリオ

1
なぜこのような基本的なコマンドにはデータベースが付属しているのですか?
masterxilo

3
@masterxiloより良い質問かもしれません-なぜこのような基本的なコマンドは、最新のオペレーティングシステムに付属していないのですか?;-)
マークトムソン


3

Perlスクリプトを確認してください。暗黙的または明示的に正規表現を使用せずに、必要なことを正確に実行します。

https://github.com/Samer-Al-iraqi/Linux-str_replace

str_replace Search Replace File # replace in File in place

STDIN | str_replace Search Replace # to STDOUT

非常に便利ですよね?そのためにはPerlを学ばなければなりませんでした。本当に必要だからです


2

パターンをエスケープすることでそれを行うことができます。このような:

keyword_raw='1/2/3'
keyword_regexp="$(printf '%s' "$keyword_raw" | sed -e 's/[]\/$*.^|[]/\\&/g')"
# keyword_regexp is now '1\/2\/3'

replacement_raw='2/3/4'
replacement_regexp="$(printf '%s' "$replacement_raw" | sed -e 's/[\/&]/\\&/g')"
# replacement_regexp is now '2\/3\/4'

echo 'a/b/c/1/2/3/d/e/f' | sed -e "s/$keyword_regexp/$replacement_regexp/"
# the last command will print 'a/b/c/2/3/4/d/e/f'

このソリューションの功績はこちら:https : //stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern

注1:これは空でないキーワードに対してのみ機能します。空のキーワードはsed(sed -e 's//replacement/')では受け入れられません。

注2:残念ながら、問題を解決するために正規表現を使用しない一般的なツールは知りません。このようなツールはRustまたはCで作成できますが、デフォルトでは存在しません。


これは、OPのポイントを完全に見逃しています。明らかに、パターンをエスケープできますが、一部のパターンではこれは退屈です。
アイスクリーム

@icecreamsword最初の行の下に私の答えを読みましたか?スクリプトは自動的にエスケープします
VasyaNovikov

1

私はいくつかの他の答えをつなぎ合わせて、これを思いつきました:

function unregex {
   # This is a function because dealing with quotes is a pain.
   # http://stackoverflow.com/a/2705678/120999
   sed -e 's/[]\/()$*.^|[]/\\&/g' <<< "$1"
}
function fsed {
   local find=$(unregex "$1")
   local replace=$(unregex "$2")
   shift 2
   # sed -i is only supported in GNU sed.
   #sed -i "s/$find/$replace/g" "$@"
   perl -p -i -e "s/$find/$replace/g" "$@"
}

改行では機能しません。また、で改行をエスケープするのに役立ちません\n。解決策はありますか?
adrelanos

1

phpのstr_replaceを使用できます。

php -R 'echo str_replace("\|!£$%&/()=?^\"'\''","replace",$argn),PHP_EOL;'<input.txt >output.txt

注:ただし'、一重引用符と二重引用符はエスケープする必要があり"ます。


0

@Nowakerと同等のNode.JS:

export FNAME='moo.txt'
export FIND='search'
export REPLACE='rpl'
node -e 'fs=require("fs");fs.readFile(process.env.FNAME,"utf8",(err,data)=>{if(err!=null)throw err;fs.writeFile(process.env.FNAME,data.replace(process.env.FIND,process.env.REPLACE),"utf8",e=>{if(e!=null)throw e;});});'

0

もう1つの「ほぼ」作業方法を示します。

viまたはvimを使用します。

置換を含むテキストファイルを作成します。

:%sno / my search string \\ "-:#2; g( '。j'); \\"> / my replacestring = \\ "bac)(o:#46; \\"> /
:バツ

次に、コマンドラインからviまたはvimを実行します。

vi -S commandfile.txt path/to/the/file

:%snoは、マジックなしで検索と置換を行うviコマンドです。

/は、選択したセパレータです。

:xはviを保存して終了します。

バックスラッシュ '\'をエスケープする必要があります。スラッシュ '/'は、たとえば疑問符 '?'に置き換えることができます。または、検索または置換文字列にない他の何か、パイプ「|」私にとってはうまくいきませんでした。

参照:https : //stackoverflow.com/questions/6254820/perform-a-non-regex-search-replace-in-vim https://vim.fandom.com/wiki/Search_without_need_to_escape_slash http://linuxcommand.org/ lc3_man_pages / vim1.html

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