複数のファイルパターンをgrepに渡す

複数のファイルパターンをgrepに渡す

bash 配列 ( ) に検索パターンのシーケンスが格納されておりptrn、これをコマンドに渡したいと考えていますgrep。どうすればよいでしょうか?

  ptrn=("FN" "DS")
  for fl in "$@"; do  # loop through number of files
    if [[ -f "$fl" ]]; then
      printf '\n%s%s%s\n\n' "$mgn" "==>  $flnm  <==" "$rst"
      grep --color "$ptrn" "$flnm"
    fi
  done

答え1

grepサブシェルを介してパターンを渡すのはどうでしょうか。例:

grep -f <(printf "%s\n" "${ptrn[@]}") FILE...

答え2

2 つのオプション:

  • 標準に準拠した方法: パターンを改行で結合し、単一の引数として指定します。

    grep -e "$(printf "%s\n" "${ptrn[@]}")" ...
    

    (この機能はPOSIX標準:「パターンリストの値は、<改行> 文字で区切られた 1 つ以上のパターンで構成されます ...")

  • 非標準ですが、それでも安全な方法: たとえば bash のように配列を持つシェルを使用する場合は、次のように引数の配列を構築しますgrep

    args=()
    for p in "${ptrn[@]}"
    do
       args+=(-e "$p")
    done
    grep "${args[@]}" ...
    

    これはフィールド分割やグロブ化の影響を受けず、一般的にはコマンドラインを変数から構築する方法

答え3

配列要素として保存されたパターン/単語にスペースやエスケープされていないシェル特殊文字が含まれていないことが保証されている場合は、bashのパラメータ展開を使用して、配列要素をgrep個別のパターンとしてに渡すことができます-e FN -e DS ...。例:

ptrn=("FN" "DS")

# Prepend "-e" to each array element
ptrn2="${ptrn[@]/#/-e }"

# Don't quote "$ptrn2" or it will be passed as a single token and wouldn't work.
grep --color $ptrn2 file

または、エスケープされていないシェル特殊文字が含まれている可能性がある場合は、|または) (すべてのスペースで分割しても失敗しない) のように使用します:

ptrn=("FN" "DS")

# Translate spaces " " single or multiple including spaces between words in a single array element into "|".
ptrn2="$(echo ${ptrn[@]} | tr " " "|")"

# -E enables extended regular expressions ... needed for this to work.
grep --color -E "$ptrn2" file

または、各正規表現パターン内の正確なスペースを保持するには、各配列要素を個別のトークンとして渡し、|(を使用してそれらの拡張正規表現を構築します。論理和) の場合は、次のようにすることができます。

ptrn=("FN" "DS")

# Append "|" to each array element.
ptrn2="$(printf '%s|' "${ptrn[@]}")"

# Delete the last character i.e. the extra "|".
ptrn2="${ptrn2::-1}"

# -E enables extended regular expressions ... needed for this to work.
grep --color -E "$ptrn2" file

関連情報