web-dev-qa-db-ja.com

グロブがbashに一致するかどうかをテストします

単一のファイルの存在を確認する場合は、test -e filenameまたは[ -e filename ]を使用してテストできます。

Globがあり、globに一致する名前のファイルが存在するかどうかを知りたいと仮定します。 globは0個のファイルと一致する場合があり(この場合は何もする必要はありません)、または1個以上のファイルと一致することができます(この場合は何かする必要があります)。 globに一致があるかどうかをテストするにはどうすればよいですか? (一致がいくつあるかは気にしませんが、ifステートメントを1つ使用してループを作成しないでください(最も読みやすいと思うためです)。

(グロブが複数のファイルに一致する場合、test -e glob*は失敗します。)

206
Ken Bloom

Bash特定のソリューション:

compgen -G "<glob-pattern>"

パターンをエスケープすると、一致するように事前に展開されます。

終了ステータスは次のとおりです。

  • 不一致の場合は1、
  • 「1つ以上の一致」の場合は0

stdoutglobに一致するファイルのリストです。
これは、簡潔さと潜在的な副作用の最小化という点で最良の選択肢だと思います。

[〜#〜] update [〜#〜]:要求された使用例。

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi
151
Brian Chrisman

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
159
flabdablet
#!/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
23
miku

好き

_exists() {
    [ -e "$1" ]
}

if exists glob*; then
    echo found
else
    echo not found
fi
_

これは読みやすく、効率的です(膨大な数のファイルがない限り)。
主な欠点は、見た目よりもはるかに微妙であるということであり、長いコメントを追加せざるを得ない場合もあります。
一致がある場合、_"glob*"_はシェルによって展開され、すべての一致はexists()に渡されます。
一致するものがない場合、_"glob*"_がexists()に渡され、そこにも存在しないことがわかります。

編集:誤検知がある可能性があります。 コメント を参照してください

18
Dan Bloch

Globfailを設定している場合は、このクレイジーを使用できます(実際には使用しないでください)

shopt -s failglob # exit if * does not match 
( : * ) && echo 0 || echo 1

または

q=( * ) && echo 0 || echo 1
8
Arcabard

test -eには、壊れたシンボリックリンクが存在しないと見なすという残念な警告があります。あなたもそれらをチェックしたいかもしれません。

function globexists {
  test -e "$1" -o -L "$1"
}

if globexists glob*; then
    echo found
else
    echo not found
fi
7
NerdMachine

さらに別の解決策があります:

if [ "$(echo glob*)" != 'glob*' ]

これは私にとってうまく機能します。見逃しているコーナーケースはありますか?

5
SaschaZorn

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
4
queria

MYYNの答えを幾分単純化するために、彼の考えに基づいて:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi
4
Ken Bloom

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操作を繰り返す必要がなく、作業したいファイルのリストがあることです。

3
Toby Speight

この憎悪はうまくいくようです:

#!/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コマンドからの空でない出力は、グロブが何かに一致したことを示します。

1
Ryan Thompson

私はこの答えを見ていなかったので、私はそれをそこに置くと思った:

set -- glob*
[ -f "$1" ] && echo "found $@"
1
Brad Howes
#!/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
0
Peter Lyons
if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

多くの一致がある場合、またはファイルアクセスが遅い場合、これは非常に時間がかかることに注意してください。

0
Florian Diesch

[ls glob* 2>/dev/null | head -n 1] && echo true

0
otocan
_set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi
_

説明

_glob*_に一致するものがない場合、_$1_には_'glob*'_が含まれます。 _-f "$1"_ファイルが存在しないため、テスト_glob*_は真になりません。

これが他の選択肢よりも優れている理由

これはshと派生物であるkshとbashで動作します。サブシェルは作成されません。 $(..)および_`...`_コマンドはサブシェルを作成します。プロセスを分岐するため、このソリューションよりも低速です。

0
joseyluis