多くの場合、ファイルを見つける必要がありますが、次のようにファイル名が何であるかわかりません。
$ find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'
ちょっと退屈です。次のように使いやすいエイリアスを作成したいと思います。
$ findany foo bar blah
私の試みは次のとおりです。
findany() {
args=("-iname" "'*$1*'")
shift
while [ $# -gt 0 ]; do
args+=("-o" "-iname" "'*$1*'")
shift
done
find ${args[@]}
}
問題は、ファイルがすぐそこにあっても結果がまったく生成されないことです。
$ ls
bar.txt blah.txt foo.txt
$ findany foo bar blah
# nothing
echo
コマンドの前に追加すると正しく表示されます。
$ findany foo bar blah
find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'
上記の出力をコピーして実行すると正常に動作します。
$ find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'
./bar.txt
./foo.txt
./blah.txt
パラメータの分割や引用に関連しているようですが、どのようにデバッグするのかわかりません。
私は主にzshを使用していますが、bashでも同じ動作を確認しました。
答え1
あなたは非常に近いです!ただし、何らかの理由でファイル名自体に一重引用符を含めると、一致しません。
また、"${args[@]}"
これが正しく機能するには、見積もりを作成する必要があります。それ以外の場合はトークン化の影響を受け、すべてのglobはfind
表示される前にシェルから拡張されます。
以下を試してみてください(特に場合bash
)。
findany() {
local args=('-iname' "*$1*")
shift
while [ "$#" -gt 0 ]; do
args+=('-o' '-iname' "*$1*")
shift
done
find . "${args[@]}"
}
答え2
zshを使用すると、次のことができます。
set -o extendedglob # usually in your ~/.zshrc, here used for (#i) for
# case insensitive matching
print -rC1 -- **/*(#i)(foo|bar|blah)*(ND)
配列からパターンを構築するには、j[|]
パラメータ拡張フラグを使用して配列の要素を連結し、パラメータ拡張|
フラグと組み合わせてグローバルパターン演算子として処理する~
か、パラメータ拡張演算子を使用して接続を実行できます。文字列内のワイルドカード文字(配列要素内にある場合でも)はパターンと見なされます。|
~
findany1() print -rC1 -- **/*(#i)(${(~j[|])argv})*(ND)
または:
findany2() print -rC1 -- **/*(#i)(${(j[|])~argv})*(ND)
たとえば、名前findany1 '??'
に2文字以上の文字を含むファイルが検索されます。を含む名前が必要または検索されます。??
findany2
findany2 '\?\?'
findany2 '[?][?]'
??
findany2
と同じ区別をするにはfind
:
findany2() (
for arg do
argv+=( -o -iname "$arg" )
shift
done
shift
find . "$@"
)
findany1() (
set -o extendedglob
for arg do
argv+=( -o -iname "${arg//(#m)[][\\?*]/\\$MATCH}" )
shift
done
shift
find . "$@"
)
find
(?
、および)として*
認識されるワイルドカード文字を(/はサポートされている唯一の参照演算子です)にエスケープします。[...]
\
\
find
fnmatch()
答え3
$ find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'
これは問題を解決する1つの方法ですが、正直なところ、次のような結果が得られます。
shopt -s globstar ## enable recursive globbing operator **
shopt -s extglob ## enable (|) pattern lists
shopt -s nocasematch ## take a guess!
echo **/*@(foo|bar|blah)*
(しかし、そうするのに助けは必要ありませんfind
)。
シェルスクリプトをすばやく作成できます。
#! /bin/bash -
shopt -s globstar ## enable recursive globbing operator **
shopt -s extglob ## enable (|) pattern lists
shopt -s nullglob ## don't error if nothing matches
shopt -s nocasematch ## take a guess!
IFS='|' # "$*" joins with the first character of IFS
pattern="**/*@(${*})*"
IFS= # do globbing but not splitting upon unquoted expansion:
matches=( $pattern )
for element in "${matches[@]}"; do
printf '%s\n' "${element}"
done
関数にしたい場合は、pattern=…
関数done
宣言に入れてください。