ファイルが存在するかどうかをチェックしようとしていますが、ワイルドカードを使用しています。これが私の例です:
if [ -f "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
二重引用符なしで試してみました。
最も簡単なのはls
の戻り値に頼ることです(ファイルが存在しないときは0以外を返します):
if ls /path/to/your/files* 1> /dev/null 2>&1; then
echo "files do exist"
else
echo "files do not exist"
fi
私はls
の出力を完全に沈黙させるためにリダイレクトしました。
編集:この答えは少し注目を集めているので(そしてコメントとして非常に有用な批評的なコメント)、これはglob展開にも頼るがls
の使用を避けた最適化です。
for f in /path/to/your/files*; do
## Check if the glob gets expanded to existing files.
## If not, f here will be exactly the pattern above
## and the exists test will evaluate to false.
[ -e "$f" ] && echo "files do exist" || echo "files do not exist"
## This is all we needed to know, so we can break after the first iteration
break
done
これは@ grok12の答えと非常によく似ていますが、リスト全体を不必要に繰り返すことを避けます。
シェルにnullglobオプションがあり、それがオンになっている場合、どのファイルとも一致しないワイルドカードパターンは、コマンドラインから完全に削除されます。これにより、lsはパス名の引数を参照せず、現在のディレクトリの内容をリストして成功しますが、これは誤りです。 GNUstatは、引数を指定しない場合、または存在しないファイルを指定する引数を指定した場合は常に失敗します。また、&>リダイレクション演算子は バシズムです
if stat --printf='' /path/to/your/files* 2>/dev/null
then
echo found
else
echo not found
fi
GNUfindの方がより良いです。これはワイルドカード検索を内部で処理し、一致するファイルが見つかるとすぐに終了し、巨大なリストの処理に時間を浪費するのではなくなります。それらのうちの1つはシェルによって拡張されました。これにより、シェルがコマンドラインバッファをオーバーフローさせる危険性も回避されます。
if test -n "$(find /dir/to/search -maxdepth 1 -name 'files*' -print -quit)"
then
echo found
else
echo not found
fi
findの非GNUバージョンでは、findのみを検索するためにここで使用されている - maxdepthオプションがない場合があります。そこに根ざしたディレクトリツリー全体ではなく、/ dir/to/search。
これが私の答えです -
files=(xorg-x11-fonts*)
if [ -e "${files[0]}" ];
then
printf "BLAH"
fi
for i in xorg-x11-fonts*; do
if [ -f "$i" ]; then printf "BLAH"; fi
done
これは複数のファイルとファイル名の空白で動作します。
次のことができます。
set -- xorg-x11-fonts*
if [ -f "$1" ]; then
printf "BLAH"
fi
これはshとその派生語:kshとbashで動作します。サブシェルは作成されません。 $(..)と `...`コマンドはサブシェルを作成します:それらはプロセスをフォークし、そしてそれらは非効率的です。もちろん、それはいくつかのファイルで動作します、そしてこの解決策は最速であるか、または最速のものに次ぐことができます。
一致しない場合も機能します。コメントの一人が言うようにnullglobを使う必要はありません。 $ 1には元のテスト名が含まれます。したがって、$ 1ファイルが存在しないため、test -f $ 1は成功しません。
更新:
さて、今私は間違いなく解決策を持っています。
files=$(ls xorg-x11-fonts* 2> /dev/null | wc -l)
if [ "$files" != "0" ]
then
echo "Exists"
else
echo "None found."
fi
> Exists
多分これは誰かを助けるでしょう:
if [ "`echo xorg-x11-fonts*`" != "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
質問はLinux/Bashに固有のものではなかったので、私はPowershellの方法を追加することを考えました - ワイルドカードを異なって扱う - あなたはそれをinのように引用符で囲みます:
If (Test-Path "./output/test-pdf-docx/Text-Book-Part-I*"){
Remove-Item -force -v -path ./output/test-pdf-docx/*.pdf
Remove-Item -force -v -path ./output/test-pdf-docx/*.docx
}
元の質問の概念はBashやLinuxだけでなく一般的に「シェル」をカバーしており、同じ質問を持つPowershellユーザーにも当てはまるので、私はこれが役に立つと思います。
厳密に言えば、「Blah」だけを印刷したいのであれば、これが解決策です。
find . -maxdepth 1 -name 'xorg-x11-fonts*' -printf 'BLAH' -quit
これは別の方法です:
doesFirstFileExist(){
test -e "$1"
}
if doesFirstFileExist xorg-x11-fonts*
then printf "BLAH"
fi
しかし、ファイル名をソートしようとはしないので、最も最適な方法は次のようになると思います。
if [ -z `find . -maxdepth 1 -name 'xorg-x11-fonts*' -printf 1 -quit` ]
then printf "BLAH"
fi
私が使っているbashコード
if ls /syslog/*.log > /dev/null 2>&1; then
echo "Log files are present in /syslog/;
fi
ありがとうございます。
これはfor
ループやls
、find
などの外部コマンドを必要としないあなたの特定の問題に対する解決策です。
if [ "$(echo xorg-x11-fonts*)" != "xorg-x11-fonts*" ]; then
printf "BLAH"
fi
お分かりのように、それはあなたが望んでいたものよりほんの少し複雑であり、シェルがglobを展開できない場合、そのglobを持つファイルが存在しないことを意味し、echo
はglobを出力します。is is、これは私達がそれらのファイルのどれかが全く存在するかどうかチェックするために単なる文字列比較をすることを可能にします。
手続きを一般化する場合は、にしますが、ファイルにはその名前やパス内にスペースが含まれている可能性があります。 glob charは、当然のことながら何も展開できません(この例では、名前が正確に xorg-x11-fontsのファイルの場合です)。
これは、bashにある以下の関数によって実現できます。
function doesAnyFileExist {
local arg="$*"
local files=($arg)
[ ${#files[@]} -gt 1 ] || [ ${#files[@]} -eq 1 ] && [ -e "${files[0]}" ]
}
あなたの例に戻ると、それはこのようにして呼び出すことができます。
if doesAnyFileExist "xorg-x11-fonts*"; then
printf "BLAH"
fi
関数を正しく機能させるには、関数自体の中でGlob展開を行う必要があります。そのため、引数を引用符で囲み、関数本体の最初の行が次のようになるようにします。関数の外側の拡張は、偽のパラメータと同様に1つにまとめられます。もう1つの方法は、複数の引数がある場合にエラーを発生させることですが、もう1つの方法は、最初の引数以外のすべてを無視することです。
関数本体の2行目は、files
varを、各配列要素に対して1つずつ、globが展開したすべてのファイル名で構成されるarrayに設定します。ファイル名にスペースが含まれている場合は問題ありません。各配列要素にはスペースも含めてそのままという名前が含まれます。
関数本体の3行目は、2つのことを行います。
最初に、配列内に複数の要素があるかどうかを確認します。もしそうなら、それはglob確かにが何かに展開されたことを意味します(最初の行で行ったことのために)。知りたかった。
1.ステップで、配列内の要素数が2未満であることがわかった場合は、1つ取得したかどうかを確認し、存在するかどうかを確認します(通常の方法)。関数引数をグロブ文字なしで考慮するには、この追加のチェックを行う必要があります。この場合、配列に含まれる要素は1つのみ、unspandedです。
私はこれを使う:
filescount=`ls xorg-x11-fonts* | awk 'END { print NR }'`
if [ $filescount -gt 0 ]; then
blah
fi
私見は、ファイル、グロブ、またはディレクトリをテストするときは、常にfind
を使うほうがいいでしょう。そうすることにおけるつまずきのブロックはfind
の終了ステータスです:すべてのパスがうまくトラバースされたなら0、そうでなければ> 0。 find
に渡した式は、その終了コードにエコーを作成しません。
次の例では、ディレクトリにエントリがあるかどうかをテストします。
$ mkdir A
$ touch A/b
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . && echo 'not empty'
not empty
A
にファイルがない場合grep
は失敗します。
$ rm A/b
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . || echo 'empty'
empty
A
が存在しない場合grep
はstderrにのみ出力されるため、find
は再び失敗します。
$ rmdir A
$ find A -maxdepth 0 -not -empty -print | head -n1 | grep -q . && echo 'not empty' || echo 'empty'
find: 'A': No such file or directory
empty
-not -empty
を他のfind
式に置き換えますが、-exec
をstdoutに出力するコマンドにする場合は注意してください。そのような場合にはもっと具体的な式をgrepしたいと思うかもしれません。
この方法はシェルスクリプトでうまく機能します。最初の質問はglob xorg-x11-fonts*
を探すことでした。
if find -maxdepth 0 -name 'xorg-x11-fonts*' -print | head -n1 | grep -q .
then
: the glob matched
else
: ...not
fi
xorg-x11-fonts*
が一致しなかった場合、またはfind
がエラーを検出した場合は、else分岐に達します。ケースを区別するために$?
を使用してください。
if [ `ls path1/* path2/* 2> /dev/null | wc -l` -ne 0 ]; then echo ok; else echo no; fi
他のファイルも切り取ることができます
if [ -e $( echo $1 | cut -d" " -f1 ) ] ; then
...
fi
どうですか?
if ls -l | grep -q 'xorg-x11-fonts.*' # grep needs a regex, not a Shell glob
then
# do something
else
# do something else
fi
Ksh、bash、およびzshシェルで新しい派手なshmancy機能を使用する(この例では、ファイル名のスペースは処理されません)。
# Declare a regular array (-A will declare an associative array. Kewl!)
declare -a myarray=( /mydir/tmp*.txt )
array_length=${#myarray[@]}
# Not found if the 1st element of the array is the unexpanded string
# (ie, if it contains a "*")
if [[ ${myarray[0]} =~ [*] ]] ; then
echo "No files not found"
Elif [ $array_length -eq 1 ] ; then
echo "File was found"
else
echo "Files were found"
fi
for myfile in ${myarray[@]}
do
echo "$myfile"
done
はい、これはPerlのような匂いがします。私がそれに参加しなかったことを嬉しく思います;)
これを試して
fileTarget="xorg-x11-fonts*"
filesFound=$(ls $fileTarget) # 2014-04-03 edit 2: removed dbl-qts around $(...)
編集2014-04-03(dbl-quotesを削除し、テストファイル 'Charlie 22.html'(2スペース)を追加しました
case ${filesFound} in
"" ) printf "NO files found for target=${fileTarget}\n" ;;
* ) printf "FileTarget Files found=${filesFound}\n" ;;
esac
テスト
fileTarget="*.html" # where I have some html docs in the current dir
FileTarget Files found=Baby21.html
baby22.html
charlie 22.html
charlie21.html
charlie22.html
charlie23.html
fileTarget="xorg-x11-fonts*"
NO files found for target=xorg-x11-fonts*
これは現在のディレクトリ、またはvar fileTarget
に検査したいパスが含まれている場合にのみ機能することに注意してください。
共有する価値があるいくつかのきちんとした解決策を見つけました。最初のものはまだ「あまりにも多くの一致がある場合これは壊れます」問題に苦しんでいます:
pat="yourpattern*" matches=($pat) ; [[ "$matches" != "$pat" ]] && echo "found"
([ ]
構文なしで配列を使用すると、配列の最初の要素が得られることを思い出してください。)
スクリプトに "shopt -s nullglob"がある場合は、単純に次のようにします。
matches=(yourpattern*) ; [[ "$matches" ]] && echo "found"
ディレクトリに大量のファイルを格納することが可能であれば、findを使用してうまく動かなくなります。
find /path/to/dir -maxdepth 1 -type f -name 'yourpattern*' | grep -q '.' && echo 'found'
ワイルドカードを使用してネットワークフォルダに大量のファイルがある場合は問題があります(速度、またはコマンドライン引数のオーバーフロー)。
私はとなった:
if [ -n "$(find somedir/that_may_not_exist_yet -maxdepth 1 -name \*.ext -print -quit)" ] ; then
echo Such file exists
fi