web-dev-qa-db-ja.com

特定のパターンに一致しないファイルがディレクトリに存在するかどうかをテストします

私はこれで多くの困難を抱えています。指定されたパターンに一致せず、trueまたはfalseを返すファイルがディレクトリに存在するかどうかをテストしようとしています。

この場合、アンダースコア_$dir_で始まらない___内のファイル。 if [ -f $dir/!(_*) ]、_if [ $dir -f -name ! _* ]_を試してみようと思いました

またはif ls $dir/!(_*) 1> /dev/null 2>&1

しかし、それは常に_Too many arguments_または_syntax error near unexpected token "("_と言うでしょう

4
obidyne
names=( "$dir"/[!_]* )

if [ -e "${names[0]}" ]; then
    echo 'there are filenames that do not start with underscore'
    printf '%d of them\n' "${#names[@]}"
fi

または、/bin/sh(およびbash)の場合:

set -- "$dir"/[!_]*

if [ -e "$1" ]; then
    echo 'there are filenames that do not start with underscore'
    printf '%d of them\n' "$#"
fi

つまり、適切なグロビングパターンを展開し、存在するものと一致するかどうかをテストします。

[!_]パターンは、アンダースコア以外のすべての文字に一致します。 正規表現[^_]に似ていますが、ファイル名のグロブパターンでは、!ではなく^を使用して文字クラスを無効にします。

パターン一致しないが一致する場合、デフォルトでは展開されないままになるため、-eテストを使用して、一致リストの最初のものが存在することを確認します。返されるリストの長さを実際にテストすることはできません。長さが1の場合は、何も一致しない可能性があるためです(nullglobシェルオプションがbashで設定されていない限り)。

通常のファイルをテストする場合は少し注意が必要です。具体的には、グロブパターンが任意の名前(ディレクトリ、通常のファイル、およびその他すべての種類のファイル)と一致するためです。しかし、これはそれを行います:

names=( "$dir"/[!_]* )

while [ "${#names[@]}" -gt 0 ] && [ ! -f "${names[0]}" ]; do
    names=( "${names[@]:1}" )
done

if [ -f "${names[0]}" ]; then
    echo 'there are at least one regular file here (or a symlink to one)'
    echo 'whose filename does not start with underscore'
fi

または、/bin/shの場合:

set -- "$dir"/[!_]*

while [ "$#" -gt 0 ] && [ ! -f "$1" ]; do
    shift
done

if [ -f "$1" ]; then
    echo 'there are at least one regular file here (or a symlink to one)'
    echo 'whose filename does not start with underscore'
fi

このアプローチでは、名前がアンダースコアで始まらない通常のファイルへのシンボリックリンクも検出されます。

ループは、一致した可能性のある通常のファイルではないファイルの名前(ディレクトリ名など)をシフトオフするために必要です。

zshシェルでは、パターン"$dir"/[^_]*(.)を使用できます。これは、通常のファイルのみに一致することが保証されています(一致する場合)。


より複雑なパターンの場合は、一致するアイテムの数を*で一致するアイテムの数と単純に比較できます。それらが異なる場合、複雑なパターンと一致しない名前があります。

bashでは、shopt -s extglobextglob Shellオプションを有効にした後、拡張グロブパターン!(PATTERN)を使用できます。一般的な形式は!(pattern1|pattern2|pattern3|etc)です。上記のように拡張の結果を調べて、何かに拡張されたかどうかを確認する必要があります。

アンダースコアで始まらない名前の例では、!(_*)拡張グロビングパターンを使用できますが、!(_)*は、*と同様に、すべての表示名に一致するため機能しないことに注意してください。

4
Kusalananda