web-dev-qa-db-ja.com

sedを使用して正規表現ではなく、固定文字列/リテラル​​として解釈します

grepには、検索文字列の正規表現の解釈をオフにする固定文字列オプション-Ffgrep)があります。 sedに同様の機能はありますか?その男には何も見つかりませんでした。別のgnu/linuxツールの推奨も問題ありません。

検索と置換の機能にsedを使用しています:sed -i "s/abc/def/g"

33
EoghanM

Sedを使用する必要がありますか? bashスクリプトを作成している場合は、次のことができます。

#!/bin/bash
pattern='abc'
replace='def'
file=/path/to/file
tmpfile="${TMPDIR:-/tmp}/$( basename "$file" ).$$"
while read -r line
do
  echo "${line//$pattern/$replace}"
done < "$file" > "$tmpfile" && mv "$tmpfile" "$file"

古いBourneShell(ksh88やPOSIX shなど)では、それほどクールではない可能性があります${var/pattern/replace}構造ですが、${var#pattern}および${var%pattern}、これを使用して文字列を分割し、再組み立てできます。それを行う必要がある場合は、さらに多くのコードが必要になりますが、それほど悪くはありません。

まだシェルスクリプトを使用していない場合は、パターン、置換、およびファイル名のパラメーターを非常に簡単に作成して、これを呼び出すことができます。 :)

PS- $ {TMPDIR:-/ tmp}構造体は、環境で設定されている場合は$ TMPDIRを使用し、変数が設定されていない場合は/ tmpを使用します。現在のプロセスのpidをファイル名の最後に貼り付けて、もう少しユニークになることを期待しています。 「現実の世界」ではおそらくmktempなどを使用する必要がありますが、これは簡単な例としては問題なく、mktempバイナリが常に利用できるとは限りません。

8
dannysauer

オプション1)正規表現文字をエスケープします。例えば。 sed 's/\$0\.0/0/g'は、出現するすべての$ 0.0を0に置き換えます。

オプション2)quotemetaと組み合わせてPerl -p -eを使用します。例えば。 Perl -p -e 's/\\./,/gi'は、出現するすべての.,に置き換えます。

次のようなスクリプトでオプション2を使用できます。

SEARCH="C++"
REPLACE="C#"
cat $FILELIST | Perl -p -e "s/\\Q$SEARCH\\E/$REPLACE/g" > $NEWLIST
5
Kim Burgaard

もしあなたがしないでくださいあなたの文字列をエスケープしたいなら、
2つのステップで目標を達成できます。

fgrep置換する行(行番号を取得)、
その後、この行を置き換えるためにsedを使用します。

例えば.

#/bin/sh
PATTERN='foo*[)*abc'    # we need it literal
LINENUMBER="$( fgrep -n "$PATTERN" "$FILE" | cut -d':' -f1 )"

NEWSTRING='my new string'
sed -i "${LINENUMBER}s/.*/$NEWSTRING/" "$FILE"
2
Bastian Bittorf

Rubyまたは長い行に反対しない場合は、次のように使用できます。

alias replace='Ruby -e "File.write(ARGV[0], File.read(ARGV[0]).gsub(ARGV[1], ARGV[2]))"'

replace test3.txt abc def

これにより、ファイル全体がメモリにロードされ、置換が実行されてディスクに保存されます。おそらく大量のファイルには使用しないでください。

2
Hubro
_Perl -i.orig -pse  'while (($i = index($_,$s)) >= 0) { substr($_,$i,length($s), $r)}'--\ 
     -s='$_REQUEST['\'old\'']' -r='$_REQUEST['\'new\'']' sample.txt
_
  • _-i.orig_バックアップによるインプレース変更。
  • _-p_デフォルトで入力ファイルから行を出力します
  • _-s_コマンドライン引数の基本的な解析を有効にする
  • _-e_このスクリプトを実行する
  • index($_,$s) _$s_文字列を検索します
  • substr($_,$i,length($s), $r)文字列を置き換えます
  • while (($i = index($_,$s)) >= 0)まで繰り返す
  • _--_ Perlパラメーターの終わり
  • _-s='$_REQUEST['\'old\'']'_、_-r='$_REQUEST['\'new\'']'_-セット_$s_、_$r_

_'_文字を「エスケープ」する必要がありますが、残りは簡単です。

注:これは 特殊文字文字列をsedに渡す方法 したがって_$_REQUEST['old']_文字列への回答として始まりましたが、この質問はもう少し適切に定式化されています。

0
Sorin

ファイル全体をメモリに読み込んでも問題がなければ、2行のbashコードでこれを行うことができます。これは非常に柔軟性があります。パターンと置換には、必要に応じて行間で一致する改行を含めることができます。また、readを使用した単純なループでは保持されない、末尾の改行またはその欠如も保持します。

mapfile -d '' < file
printf '%s' "${MAPFILE//"$pat"/"$rep"}" > file

完全を期すために、ファイルにnullバイト(\0)、上記を拡張する必要があり、

mapfile -d '' < <(cat file; printf '\0')
last=${MAPFILE[-1]}; unset "MAPFILE[-1]"
printf '%s\0' "${MAPFILE[@]//"$pat"/"$rep"}" > file
printf '%s' "${last//"$pat"/"$rep"}" >> file
0
Grisha Levit