> find /etc -name 'shells'
/etc/shells # good !!
> SEARCH="-name 'shells'"; find /etc $SEARCH
# nothing found - bad !!
「検索」コマンドが変数のパラメーターを取得できないのはなぜですか?
他のコマンドは、そのようなモードで正常に機能します。おそらくスペースと構文解析に関連しています。最初に変数にパラメータを作成してから、このパラメータを使用して「検索」を実行するにはどうすればよいですか?
明確にするために、-name xxxx -o -name yyyyy -o -name zzzzzのチェーンを作成し、1回の実行ですべてのファイルを検索します。
あなたの問題は、単純な引用符がそのように解釈されるのではなく、あなたのパラメータにあるものとして解釈されることです。
あなたはこれを実行したと思います:
find /etc -name 'shells'
実際にこれを実行したとき:
find /etc -name \'shells\'
覚えておいてください:bashでは、二重引用符内の単純引用符は無視されません。
したがって、解決策は単純な引用符を付けないことです。
SEARCH="-name shells"; find /etc $SEARCH
より良い解決策は、引用符を使用してからevalを使用することです。
SEARCH="-name 'shells'"; eval " find /etc $SEARCH"
セキュリティの問題:決して、eval引数でユーザー提供の情報を使用することはありません。
試す
eval find /etc $SEARCH
eval
は避けることを強くお勧めします-単純なテストではうまく機能する傾向がありますが、本番環境では予期しないシェルメタキャラクターが表示され、大混乱を引き起こします。また、文字列にユーザー入力が含まれている場合、セキュリティの問題が発生することが事実上保証されています。ファイルパターンリストに誰かがx'$(rm /somethingimportant)'y
を追加できたらどうなるか考えてみてください。
コマンドを動的に構築するこのような状況では、bash配列の方がはるかに優れた方法です。次のようなものを使用します:
namepatterns=(-name xxxx)
namepatterns+=(-o -name yyyyy -o -name "*.txt") # quotes prevent wildcard expansion
while read pattern; do
namepatterns+=(-o -name "$pattern")
done <patternfile.txt
find /etc "${namepatterns[@]}"
"${array[@]}"
イディオムは、引用符で囲まれていない変数参照で発生する問題のある解析(ワード分割、ワイルドカード展開)を行わずに、配列の各要素をシェルワードとして扱います。
ところで、上記の例では、最初の-name xxxx
プライマリを、その前に-o
を付けずに配列に追加することで、少し騙しました。配列を完全にループで構築している場合、これはトリッキーになります。
namepatterns=()
while read pattern; do
namepatterns+=(-o -name "$pattern")
done <patternfile.txt
# At this point the array starts with "-o" -- not what you want
# So use array slicing to remove the first element:
namepatterns=("${namepatterns[@]:1}")
find /etc "${namepatterns[@]}"
BashFAQ#50:コマンドを変数に入れようとしていますが、複雑なケースは常に失敗します! コマンドを作成および保存するための詳細な説明とオプションについては、を参照してください。