grep の基本/拡張 posix 正規表現文字列からメタ文字をエスケープする

grep の基本/拡張 posix 正規表現文字列からメタ文字をエスケープする

grepに渡す前に、変数内の文字列のすべてのメタ文字をエスケープできますか?以前もSEで同様の質問を受けたことがわかっています(ここ)と良い説明ここしかし、Perlパターンの代わりにデフォルト/拡張POSIX正規表現パターンを使用できるかどうか疑問に思います。 (現在、私は解決策に飛び込むのではなく、最初に理解するためにPerl正規表現の構文を読んでいます。)

これが必要なのはなぜですか?(元、回答不要)

大容量ファイルを分割するための小さなスクリプトを作成しようとしていますが、ファイルをfile_name.ext.000file_name.ext.001...etcに分割しましたが、うまく動作します。今、私はすでに分割されたファイルを分割するのが好きではありません(たとえば、ファイル名の拡張子は3文字で、すべて数字で、サイズの合計は元のファイルサイズと同じです。)file_name.ext.*通常のシェル拡張子を使用してファイルなので、再分割する必要もありますではなく、全体のサイズも一致しないため、名前が数字のファイルのみを確認し、file_name.ext.ext2これらの部分のファイルサイズを見つける現在の式は次のとおりです。file_name.ext.######

FILE_SIZE_EXISTING=$( (find "$DESTINATION" -type f -regextype posix-extended -regex "^$DESTINATION/$FILE_BASENAME(\.[[:digit:]]{3})?$" -print0 | xargs -0 stat --printf="%s\\n" 2>/dev/null || echo 0) | paste -sd+ | bc)

これは単純なファイル名に適用されます。ただし、カラフルな名前([ ]などを含む)がある場合は機能しません。解決策はありますか?私はシェルスクリプトに初めて触れたので、Perlについてはよくわかりません。

答え1

特殊文字引用方法(移植可能)

次のコードスニペットは、拡張正規表現の各特殊文字の前にバックスラッシュを追加し、そのsed文字のいずれかが出てくる場合はバックスラッシュとその文字に置き換えます。][()\.^$?*+

raw_string='test[string]\.wibble'
quoted_string=$(printf %s "$raw_string" | sed 's/[][()\.^$?*+]/\\&/g')

$raw_stringこれにより、;から末尾の改行文字が削除されます。これが問題の場合は、最後に怠惰​​な文字を追加してからその文字を削除して、文字列が改行文字で終わらないことを確認してください。

quoted_string=$(printf %sa "$raw_string" | sed 's/[][()\.^$?*+]/\\&/g')
quoted_string=${quoted_string%?}

特殊文字を引用する方法(bashまたはzsh)

Bashとzshには、文字列がそれほど長くない場合は、より高速なパターン置換機能があります。置換は文字列である必要があるため、各文字を別々に置き換える必要があるため、これは面倒です。まず、バックスラッシュをエスケープする必要があります。

quoted_string=${raw_string//\\//\\\\}
for c in \[ \] \( \) \. \^ \$ \? \* \+; do
  quoted_string=${quoted_string//"$c"/"\\$c"}
done

特殊文字を引用する方法(ksh93)

Kshの文字列置換構成は、bashおよびzshの縮小バージョンよりも強力です。スキーマのグループへの参照をサポートします。

quoted_string=${raw_string//@([][()\.^$?*+])/\\\1}

あなたが本当に欲しいものは何ですか?

ここでは必要ありませんfind。シェルパターンは、3 桁の数字で終わるファイルを一致させるのに十分です。部品ファイルが存在しない場合、glob パターンは拡張されません。ファイルサイズを追加する簡単な方法もあります。stat呼び出すことができます(ほとんどのシステムでファイルを開き、バイトを読み取らずにファイルサイズを確認するwc -c通常のファイルから)。wc

set -- "$DESTINATION/$FILE_BASENAME".[0-9][0-9][0-9]
case $1 in
  *\]) # The glob was left intact, so no part exists
    do_split …;;
  *) # The glob was expanded, so at least one part exists
    FILE_SIZE_EXISTING=$(wc -c "$@" | sed -n '$s/[^0-9]//gp')
    if [ "$FILE_SIZE_EXISTING" -ne "$(wc -c <"$DESTINATION/$FILE_BASENAME")" ]; then
      do_split …
    fi

フルサイズテストは信頼性が低下します。ファイルが変更されたがサイズが同じままの場合、古い部分が発生します。ファイルが全く変わらなくても大丈夫です。唯一のリスクは、コンテンツの一部が切り捨てられたり失われたりする可能性があることです。

関連情報