私は何度も何度もこの問題を抱えていました。正しいファイルと正確に一致するグロブがありますが、Command line too long
が発生します。特定の状況で機能するfind
とgrep
の組み合わせに変換するたびに、100%の等価ではありません。
例えば:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
グロブをfind
式に変換するためのツールがありませんか?または、サブディレクトリで同じグロブと一致せずにグロブと一致するfind
のオプションはありますか(たとえば、foo/*.jpg
はbar/foo/*.jpg
との一致が許可されていません)?
Argument-list-is-too-longエラーが発生することが問題である場合は、ループまたは組み込みのシェルを使用します。 _command glob-that-matches-too-much
_はエラーになる可能性がありますが、_for f in glob-that-matches-too-much
_はエラーになりません。
_for f in foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
do
something "$f"
done
_
ループは非常に遅いかもしれませんが、動作するはずです。
または:
_printf "%s\0" foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg |
xargs -r0 something
_
(printf
はほとんどのシェルに組み込まれているため、上記はexecve()
システムコールの制限を回避します)
_$ cat /usr/share/**/* > /dev/null
zsh: argument list too long: cat
$ printf "%s\n" /usr/share/**/* | wc -l
165606
_
Bashでも動作します。これがどこに文書化されているのか正確にはわかりません。
Vimの glob2regpat()
とPythonの fnmatch.translate()
はどちらもグロブを正規表現に変換できますが、どちらも_.*
_ for _*
_、_/
_全体で一致。
あなたはあなたの要件に一致する検索のための正規表現を書くことができます:
find . -regextype egrep -regex './foo[^/]*bar/quux[A-Z](\.bak)?/pic[0-9][0-9][0-9][0-9][^/]?\.jpg'
私の他の回答 に関する注記を一般化すると、質問に対するより直接的な回答として、このPOSIX sh
スクリプトを使用して、グロブをfind
式に変換できます:
#! /bin/sh -
glob=${1#./}
shift
n=$#
p='./*'
while true; do
case $glob in
(*/*)
set -- "$@" \( ! -path "$p" -o -path "$p/*" -o -name "${glob%%/*}" -o -Prune \)
glob=${glob#*/} p=$p/*;;
(*)
set -- "$@" -path "$p" -Prune -name "$glob"
while [ "$n" -gt 0 ]; do
set -- "$@" "$1"
shift
n=$((n - 1))
done
break;;
esac
done
find . "$@"
one標準sh
グロブで使用するため(brace展開を使用する例の2つのグロブではない ):
glob2find './foo*bar/quux[A-Z].bak/pic[0-9][0-9][0-9][0-9]?.jpg' \
-type f -exec cmd {} +
(これは、.
と..
以外のドットファイルまたはドットディレクトリを無視せず、ファイルのリストをソートしません)。
これは.
または..
コンポーネントなしで、現在のディレクトリに関連するグロブでのみ機能します。少し努力すれば、グロブよりも任意のグロブに拡張できます... glob2find 'dir/*'
がdir
を検索しないように最適化することもできます。パターン。