281

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

グロブがあり、その名前がグロブと一致するファイルが存在するかどうかを知りたいとします。globは0個のファイルと一致するか(この場合は何もする必要はありません)、1つ以上のファイルと一致する可能性があります(この場合は何かをする必要があります)。グロブに一致するものがあるかどうかをテストするにはどうすればよいですか?if(一致するものがいくつあるかは関係ありません。1つのステートメントでループを作成せずにこれを実行できるとよいでしょう(最も読みやすいと思うからです)。

test -e glob*globが複数のファイルと一致する場合は失敗します。)

4

20 に答える 20

243

Bash固有のソリューション:

compgen -G "<glob-pattern>"

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

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

  • 一致しない場合は1、
  • '1つ以上の一致'の場合は0

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

例:

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi
于 2015-12-10T06:36:29.147 に答える
189

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アクションの代わりに、明示的な-print -quitアクションが検索に使用されるため、検索条件に一致する最初のファイルが見つかるとすぐにfindが終了します。多くのファイルが一致する場合、これはまたはよりもはるかに高速に実行されるはずであり、拡張されたコマンドラインを過剰に詰め込む可能性も回避します(一部のシェルには4Kの長さ制限があります)。echo glob*ls glob*

findがやり過ぎだと感じ、一致する可能性のあるファイルの数が少ない場合は、statを使用します。

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi
于 2010-11-24T07:24:42.860 に答える
26
#!/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
于 2010-05-30T03:39:07.167 に答える
26

好き

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

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

これは、読み取り可能で効率的です(ファイルの数が非常に多い場合を除く)。
主な欠点は、見た目よりもはるかに微妙であり、長いコメントを追加せざるを得ない場合があることです。
一致するものがある場合"glob*"、シェルによって展開され、すべての一致がに渡されexists()ます。これにより、最初の一致がチェックされ、残りは無視されます。
一致するものがない場合は、"glob*"に渡されexists()、そこにも存在しないことがわかります。

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

于 2013-03-20T04:09:49.380 に答える
11

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

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

また

q=( * ) && echo 0 || echo 1
于 2014-06-28T14:04:35.380 に答える
8

test -eには、壊れたシンボリックリンクが存在しないと見なすという不幸な警告があります。したがって、それらも確認することをお勧めします。

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

if globexists glob*; then
    echo found
else
    echo not found
fi
于 2013-11-08T16:16:37.690 に答える
6

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

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

これは私にとってうまく機能します。私が見逃したいくつかのコーナーケースがあるかもしれません。

于 2015-11-06T14:39:30.280 に答える
4

ミクの考えに基づいて、ミクの答えをいくらか単純化するために:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
fi
于 2010-05-30T04:07:42.607 に答える
4

flabdabletの回答に基づくと、私にとって最も簡単な(必ずしも最速であるとは限らない)のは、次のように、シェルにglob拡張を残したまま、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
于 2013-03-01T09:05:24.577 に答える
3

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

于 2018-05-03T11:23:34.100 に答える
2
#!/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
于 2010-05-30T03:33:22.580 に答える
2
set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

説明

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

なぜこれが代替案よりも優れているのか

これはshとその派生物(KornShellとBash)で機能します。サブシェルは作成されません。コマンドはサブシェルを作成します$(..)`...`それらはプロセスをフォークするため、このソリューションよりも低速です。

于 2018-07-18T12:24:35.683 に答える
2

Bashでこのように(を含むテストファイルpattern):

shopt -s nullglob
compgen -W *pattern* &>/dev/null
case $? in
    0) echo "only one file match" ;;
    1) echo "more than one file match" ;;
    2) echo "no file match" ;;
esac

compgen -Gより多くのケースをより正確に識別できるため、:よりもはるかに優れています。

1つのワイルドカードでのみ機能し*ます。

于 2020-06-09T16:56:09.660 に答える
1

この忌まわしきはうまくいくようです:

#!/usr/bin/env bash
shopt -s nullglob
if [ "`echo *py`" != "" ]; then
    echo "Glob matched"
else
    echo "Glob did not match"
fi

おそらくshではなくbashが必要です。

これが機能するのは、nullglobオプションを使用すると、一致するものがない場合にglobが空の文字列と評価されるためです。したがって、echoコマンドからの空でない出力は、globが何かに一致したことを示します。

于 2010-08-30T00:37:16.790 に答える
0

一般的な信念は、それ[ -f file* ]は機能しないということです。事実、それは機能します。個人的には、特定の場所にある1つのファイルの名前を取得したい場合などに非常に便利です。たとえば、名前にバージョン番号が含まれているファイルなどです。このコードを考えてみましょう:

if [ -f "$ROOT"/lib64/libc-*.so ] ;then
  LIBC=$(basename -- "$ROOT"/lib64/libc-*.so .so)
else
  echo "libc ??" ; exit 1
fi

ところで、ShellCheckは、そのような使用を見るとファウルを叫びます。:-)私は彼らがそれを修正することを望みます!

SC2144。-eはグロブでは機能しません。forループを使用します。

于 2021-08-11T04:34:21.267 に答える
-1
(ls glob* &>/dev/null && echo Files found) || echo No file found
于 2010-05-30T03:37:48.550 に答える
-1

Bashの拡張グロブ(extglob)の解決策:

bash -c $'shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

終了ステータスは、一致するものが1つ以上ある場合は0、一致しない場合はゼロ以外(2)です。標準出力には、一致するファイル(および引用符で囲まれたスペースを含むファイル名)の改行で区切られたリストが含まれます。

または、わずかに異なります:

bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'

ベースのソリューションとの違いls:おそらくより高速(測定されていない)、出力で引用符で囲まれていないスペースを含むファイル名、一致しない場合(2:shrug:)でコード1を終了します。

使用例:

歯が立たない:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?"
/bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory
exit status: 2

少なくとも1つの一致:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?"
'video1 with spaces.mp4'
video2.mp4
video3.mp4
exit status: 0

使用される概念:

  • ls'終了コードの動作(効率と出力制御のため-Uに追加)。-1
  • extglob現在のシェルでは有効になりません(多くの場合、望ましくありません)。
  • $プレフィックスを使用して、\nが解釈されるようにします。これにより、拡張グロブパターンが-とは異なる行にshopt -s extglob表示されます。そうしないと、拡張グロブパターンが構文エラーになります。

注1:他の回答で提案されているアプローチは、ブレースの拡張compgen -G "<glob-pattern>"ではスムーズに機能しないように思われるため、このソリューションに取り組みました。それでも、より高度なグロブ機能が必要でした。

注2:拡張グロブ構文の素敵なリソース:extglob

于 2020-12-09T13:00:06.950 に答える
-2
if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

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

于 2010-05-30T03:43:42.950 に答える
-2

ls | grep -q "glob.*"

最も効率的な解決策ではありませんが(ディレクトリに大量のファイルがある場合は遅くなる可能性があります)、シンプルで読みやすく、正規表現がプレーンなBashグロブパターンよりも強力であるという利点もあります。

于 2016-04-08T10:58:14.270 に答える
-4
[ `ls glob* 2>/dev/null | head -n 1` ] && echo true
于 2017-07-27T12:03:03.963 に答える