シェルスクリプト、find -name、およびワイルドカード拡張

シェルスクリプト、find -name、およびワイルドカード拡張

find -namesh私のスクリプトで使用しようとしています。以前に計算された条件の複雑な引数。単純化すると、

cond="-name '*.txt*"
find . $cond -ls

しかし、今私が経験している問題は、のワイルドカードが呼び出さ$condれる前にシェルによって拡張されるかfindfind

これをテストするために、空のテストディレクトリで次のことを行いました。

touch a.txt b.txt c.dat

それから繰り返し

cond="-name '*.txt'"; echo $cond; find . $cond

$cond私が考えることができるすべての種類の引用/エスケープを使用して異なる値を使用します。

.4つのエントリ(ディレクトリを含む)がすべて取得されましたが、ファイルが見つからないか不明な基本またはオペレータfindというメッセージが表示されます。b.txtもちろん、正しい出力は2つのテキストファイルでなければなりません。

どのようなヒントがありますか?私は基本的なものを見逃していると確信しています。

答え1

Bourneに似たシェル(除外zsh)では、リストコンテキストで引用されていない変数拡張を維持することは次のとおりです。分割+グローバルオペレーター。存在する:

cond="-name '*.txt'"; echo $cond

の内容は、$condまず$IFS特殊変数の値に基づいて分割されます。デフォルトでは、ASCII スペース、タブ、改行文字です。

だからそれは分けるを入力-nameして'*.txt'。それから全体的な状況部分的に適用されます。すべて性格ワイルドカード文字が含まれている場合(*ここで2番目の文字)、単語はパターンに一致するファイルのリストに展開されるか、一致するファイルがない場合は変更されずに残ります。したがって、一致するファイルが存在しない場合は、現在のディレクトリで名前が終わるか拡張されるファイルのリストが展開されます'*.txt''.txt''*.txt'

この単語リストは別の引数としてに渡されますecho。一致するファイルがない場合、および3echoつの引数が受け取ります。"echo""-name""'*.txt'"

もちろん、findコマンドにも同様に適用されます。

コマンドはパラメータsumをfind受け取りたいので、調整する必要があります。-name*.txt分割+グローバルオペレーター。

$IFSで使用する区切り文字と一致する値が必要です$cond。たとえば、

cond='-name:*.txt'
IFS=':'

そしてあなたは望んでいません。全体的な状況~の一部分割+グローバル演算子なので、次の方法で無効にする必要があります。

set -f

だからそれは次のようになります:

cond='-name:*.txt'
IFS=:; set -f
find . $cond -ls

またはこれを行うこともできます:

cond='-name *.txt'
set -f
find . $cond -ls

そして、$IFSデフォルト値が変更されていないと仮定します。

あるいは、シェルが配列をサポートしている場合は、スカラー変数に依存し、拡張時にシェルが配列を分割することを期待する代わりに、配列を使用できます。

これはksh93、または次mkshに適用されます。bashzsh

cond=(-name '*.txt') # an array with two elements: "-name" and "*.txt"
find . "${cond[@]}" -ls # elements of the array expanded as separate arguments
                        # to find.

関連情報