私はこれのために多くの困難を経験しています。ディレクトリに特定のパターンと一致しないファイルがあるかどうかをテストしようとしており、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 "("
答え1
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
シェルを有効にするオプションを使用した後、拡張グロービングモードを使用できます。一般的な形式は、上記のように拡張結果を確認して、どんなものにも拡張されることを確認する必要があります。!(PATTERN)
extglob
shopt -s extglob
!(pattern1|pattern2|pattern3|etc)
アンダースコアで始まらない名前の例では、!(_*)
拡張globingパターンを使用できますが、これは表示されている!(_)*
すべての名前と一致するため、機能しないことに注意してください*
。