単一のファイルの存在を確認する場合は、test -e filename
または[ -e filename ]
を使用してテストできます。
Globがあり、globに一致する名前のファイルが存在するかどうかを知りたいと仮定します。 globは0個のファイルと一致する場合があり(この場合は何もする必要はありません)、または1個以上のファイルと一致することができます(この場合は何かする必要があります)。 globに一致があるかどうかをテストするにはどうすればよいですか? (一致がいくつあるかは気にしませんが、if
ステートメントを1つ使用してループを作成しないでください(最も読みやすいと思うためです)。
(グロブが複数のファイルに一致する場合、test -e glob*
は失敗します。)
Bash特定のソリューション:
compgen -G "<glob-pattern>"
パターンをエスケープすると、一致するように事前に展開されます。
終了ステータスは次のとおりです。
stdout
はglobに一致するファイルのリストです。
これは、簡潔さと潜在的な副作用の最小化という点で最良の選択肢だと思います。
[〜#〜] update [〜#〜]:要求された使用例。
if compgen -G "/tmp/someFiles*" > /dev/null; then
echo "Some files exist."
fi
Nullglobシェルオプションは確かにバシズムです。
Nullglob状態の退屈な保存と復元の必要性を回避するために、globを展開するサブシェル内でのみ設定します。
if test -n "$(shopt -s nullglob; echo glob*)"
then
echo found
else
echo not found
fi
移植性を高め、より柔軟なグロビングを行うには、findを使用します。
if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
echo found
else
echo not found
fi
明示的な-print -quitアクションは、デフォルトの暗黙的な-printアクションの代わりにfindに使用されるため、find検索条件に一致する最初のファイルが見つかったらすぐに終了します。多くのファイルが一致する場合、これはecho glob*
または ls glob*
また、拡張されたコマンドラインを詰め込む可能性を回避します(一部のシェルには4Kの長さ制限があります)。
findが過剰に感じられ、一致する可能性のあるファイルの数が少ない場合は、statを使用します。
if stat -t glob* >/dev/null 2>&1
then
echo found
else
echo not found
fi
#!/usr/bin/env bash
# If it is set, then an unmatched glob is swept away entirely --
# replaced with a set of zero words --
# instead of remaining in place as a single Word.
shopt -s nullglob
M=(*px)
if [ "${#M[*]}" -ge 1 ]; then
echo "${#M[*]} matches."
else
echo "No such files."
fi
好き
_exists() {
[ -e "$1" ]
}
if exists glob*; then
echo found
else
echo not found
fi
_
これは読みやすく、効率的です(膨大な数のファイルがない限り)。
主な欠点は、見た目よりもはるかに微妙であるということであり、長いコメントを追加せざるを得ない場合もあります。
一致がある場合、_"glob*"
_はシェルによって展開され、すべての一致はexists()
に渡されます。
一致するものがない場合、_"glob*"
_がexists()
に渡され、そこにも存在しないことがわかります。
編集:誤検知がある可能性があります。 コメント を参照してください
Globfailを設定している場合は、このクレイジーを使用できます(実際には使用しないでください)
shopt -s failglob # exit if * does not match
( : * ) && echo 0 || echo 1
または
q=( * ) && echo 0 || echo 1
test -eには、壊れたシンボリックリンクが存在しないと見なすという残念な警告があります。あなたもそれらをチェックしたいかもしれません。
function globexists {
test -e "$1" -o -L "$1"
}
if globexists glob*; then
echo found
else
echo not found
fi
さらに別の解決策があります:
if [ "$(echo glob*)" != 'glob*' ]
これは私にとってうまく機能します。見逃しているコーナーケースはありますか?
flabdabletの答え に基づいて、私にとっては、find自体を使用するのが最も簡単な(必ずしも最速ではない)ように見える次のようなシェル上のグロブ展開:
find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"
またはif
のように:
if find $yourGlob -quit &> /dev/null; then
echo "MATCH"
else
echo "NOT-FOUND"
fi
MYYNの答えを幾分単純化するために、彼の考えに基づいて:
M=(*py)
if [ -e ${M[0]} ]; then
echo Found
else
echo Not Found
fi
Bashでは、配列にグロブできます。グロブが一致しなかった場合、配列には既存のファイルに対応しない単一のエントリが含まれます。
#!/bin/bash
shellglob='*.sh'
scripts=($shellglob)
if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi
注:nullglob
が設定されている場合、scripts
は空の配列になります。[ "${scripts[*]}" ]
または[ "${#scripts[*]}" != 0 ]
代わりに。 nullglob
の有無にかかわらず動作する必要のあるライブラリを作成している場合は、
if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]
このアプローチの利点は、glob操作を繰り返す必要がなく、作業したいファイルのリストがあることです。
この憎悪はうまくいくようです:
#!/usr/bin/env bash
shopt -s nullglob
if [ "`echo *py`" != "" ]; then
echo "Glob matched"
else
echo "Glob did not match"
fi
おそらくshではなくbashが必要です。
これは、nullglobオプションにより、グロブが一致しない場合に空の文字列に評価されるためです。したがって、echoコマンドからの空でない出力は、グロブが何かに一致したことを示します。
私はこの答えを見ていなかったので、私はそれをそこに置くと思った:
set -- glob*
[ -f "$1" ] && echo "found $@"
#!/bin/bash
set nullglob
touch /tmp/foo1 /tmp/foo2 /tmp/foo3
FOUND=0
for FILE in /tmp/foo*
do
FOUND=$((${FOUND} + 1))
done
if [ ${FOUND} -gt 0 ]; then
echo "I found ${FOUND} matches"
else
echo "No matches found"
fi
if ls -d $glob > /dev/null 2>&1; then
echo Found.
else
echo Not found.
fi
多くの一致がある場合、またはファイルアクセスが遅い場合、これは非常に時間がかかることに注意してください。
[ls glob* 2>/dev/null | head -n 1
] && echo true
_set -- glob*
if [ -f "$1" ]; then
echo "It matched"
fi
_
_glob*
_に一致するものがない場合、_$1
_には_'glob*'
_が含まれます。 _-f "$1"
_ファイルが存在しないため、テスト_glob*
_は真になりません。
これはshと派生物であるkshとbashで動作します。サブシェルは作成されません。 $(..)
および_`...`
_コマンドはサブシェルを作成します。プロセスを分岐するため、このソリューションよりも低速です。