いくつかの変数を使ってfindを呼び出そうとします。これまで私はこれを持っています:
DIRECTORY="./ "
FILENAME=-regex" .*test.*"
find $DIRECTORY $FILENAME
良い結果。ファイル名を次のように変更した場合:
FILENAME=-regex" .*"
ディレクトリ内のすべてのファイルを一覧表示するには、次のエラーが発生します。
find: paths must precede expression: ..
私は何が間違っていましたか?
答え1
変数の内容FILENAME
は
-regex .*test.*
引用符は変数値の一部ではなく、シェル構文の一部です。シェルは、これが割り当てであることを発見する前に行を解析し、引用符を解釈します。
line を実行すると、find $DIRECTORY $FILENAME
まず$FILENAME
その値に置き換えられます。その後、シェルは変数値に対して2段階の拡張を実行します。つまり、変数にスペースを含む別の単語(必要に応じて)に分割し、各単語に対してワイルドカード(つまりワイルドカード拡張)を実行して、次のように拡張.*
します。現在ディレクトリにあるファイルポイントで始まるファイル名のリスト。
.*test.*
パターンはどのファイルとも一致しないため、パターン自体に拡張されるため、最初のコードスニペットに問題はありません。
複数の単語を保存する必要がある場合、安定した解決策は文字列変数の代わりに配列変数を使用することです。
DIRECTORY="./"
EXPRESSION=("-regex" ".*test.*")
find "$DIRECTORY" "${EXPRESSION[@]}"
または複数のディレクトリを許可する場合:
DIRECTORIES=("./")
EXPRESSION=("-regex" ".*test.*")
find "${DIRECTORIES[@]}" "${EXPRESSION[@]}"
"${EXPRESSION[@]}"
配列の要素のリストに展開されます(別々の単語として表示されます)。
"$foo"
"$(foo)"
値のトークン化とワイルドカードを指定したくない限り、変数置換とコマンド置換の周りには常に二重引用符を使用する必要があります。
ここではbashを使用しているので、配列は正しい解決策です。配列のないシェルにはいくつかの可能性があります。実際には配列変数である位置パラメータを使用できますが、これは他の目的に使用しない場合にのみ可能です。
set -- "./" # start with the directory
set -- "$@" -regex '.*' # add the expression
find "$@" # go
別のアプローチは、後でトークン化とワイルドカードを準備するために変数の内容を適切に引用することです。?*[
ワイルドカード文字()の前にバックスラッシュを使用して、文字通り解釈することができます。
DIRECTORY=./
EXPRESSION='-regex .\*'
find "$DIRECTORY" $EXPRESSION
別のアプローチは、ワイルドカードを無効にすることですset -f
。このfind
行を実行する前に。set +f
後で必要な場合は、必ず電源を入れてください。トークン化を使用するため、述語引数の一部として空白文字を渡すことはできませんfind
。
DIRECTORY=./
EXPRESSION='-regex .*'
set -f
find "$DIRECTORY" $EXPRESSION
また、コマンドを変数に入れようとしていますが、複雑な場合は常に失敗します。 bash FAQで。
答え2
誰でも
directory=.
match=(-regex '.*test.*')
find "$directory" "${match[@]}"
または(ここで「、」を使用して強調表示):
directory=.
match='-regex,.*test.*'
IFS=,
set -f
find "$directory" $match
または:
directory=.
match="-regex '.*test.*'"
eval 'find "$directory" '"$match"
答え3
変数への参照はありません。したがって、シェルが見るのは
find ./ -regex .*
そしてそれは.*
。. ..