Programing

글로브가 bash에서 일치하는지 테스트

lottogame 2020. 5. 5. 19:33
반응형

글로브가 bash에서 일치하는지 테스트


나는 하나의 파일의 존재를 확인하려는 경우, 나는 그것을 사용하기 위해 테스트 할 수 있습니다 test -e filename또는 [ -e filename ].

글로브가 있고 글로브와 이름이 일치하는 파일이 있는지 알고 싶습니다. glob은 0 개의 파일과 일치하거나 (이 경우 아무 것도 할 필요가 없음) 1 개 이상의 파일과 일치 할 수 있습니다 (이 경우 무언가를 수행해야 함). 글로브에 일치하는 것이 있는지 어떻게 테스트 할 수 있습니까? (나는 얼마나 많은 일치 항목이 있는지 상관하지 않으며 하나의 if명령문으로 루프 없이이 작업을 수행 할 수 있다면 가장 좋습니다 (간단히 읽을 수 있기 때문에).

( test -e glob*글로브 파일이 둘 이상 일치하면 실패합니다.)


배쉬 전용 솔루션 :

compgen -G "<glob-pattern>"

패턴을 이스케이프하면 패턴이 미리 확장됩니다.

종료 상태는 다음과 같습니다.

  • 일치하지 않는 경우 1
  • '하나 이상의 일치 항목'은 0

stdoutglob와 일치하는 파일 목록입니다 .
간결함과 잠재적 부작용 최소화 측면에서 이것이 최선의 선택이라고 생각합니다.

업데이트 : 사용 요청 예.

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

nullglob 쉘 옵션은 실제로 bashism입니다.

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 조치 대신 찾기에 사용 되므로 찾기 기준과 일치하는 첫 번째 파일을 찾은 즉시 찾기 가 종료됩니다. 많은 파일이 일치하는 경우 또는 이보다 훨씬 빠르게 실행되어야 하며 확장 된 명령 행을 과도하게 채울 가능성을 피할 수 있습니다 (일부 쉘의 길이 제한은 4K입니다).echo glob*ls glob*

경우 찾기가 과도 같은 느낌 가능성에 맞게 파일의 수가 작고, 사용 합계 :

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

This is both readable and efficient (unless there are a huge number of files).
The main drawback is that it's much more subtle than it looks, and I sometimes feel compelled to add a long comment.
If there's a match, "glob*" is expanded by the shell and all the matches are passed to exists(), which checks the first one and ignores the rest.
If there's no match, "glob*" is passed to exists() and found not to exist there either.

Edit: there may be a false positive, see comment


If you have globfail set you can use this crazy (which you really should not)

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

or

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

test -e has the unfortunate caveat that it considers broken symbolic links to not exist. So you may want to check for those, too.

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

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

I have yet another solution:

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

This works nicely for me. Are there some corner cases I miss?


To simplify The MYYN's answer somewhat, based on his idea:

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

Based on flabdablet's answer, for me it looks like easiest (not necessarily fastest) is just to use find itself, while leaving glob expansion on shell, like:

find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"

Or in if like:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi

In Bash, you can glob to an array; if the glob didn't match, your array will contain a single entry that doesn't correspond to an existing file:

#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi

Note: if you have nullglob set, scripts will be an empty array, and you should test with [ "${scripts[*]}" ] or with [ "${#scripts[*]}" != 0 ] instead. If you're writing a library that must work with or without nullglob, you'll want

if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]

An advantage of this approach is that you then have the list of files you want to work with, rather than having to repeat the glob operation.


This abomination seems to work:

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

It probably requires bash, not sh.

This works because the nullglob option causes the glob to evaluate to an empty string if there are no matches. Thus any non-empty output from the echo command indicates that the glob matched something.


I did not see this answer, so I thought I'd put it out there:

set -- glob*
[ -f "$1" ] && echo "found $@"

if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

Note that this can be very time cosuming if there are a lot of matches or file access is slow.


#!/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

set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi

Explanation

When there isn't a match for glob*, then $1 will contain 'glob*'. The test -f "$1" won't be true because the glob* file doesn't exist.

Why this is better than alternatives

This works with sh and derivates: ksh and bash. It doesn't create any sub-shell. $(..) and `...` commands create a sub-shell; they fork a process, and therefore are slower than this solution.


(ls glob* &>/dev/null && echo Files found) || echo No file found

ls | grep -q "glob.*"

Not the most efficient solution (if there's a ton of files in the directory it might be slowish), but it's simple, easy to read and also has the advantage that regexes are more powerful than plain bash glob patterns.


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

참고URL : https://stackoverflow.com/questions/2937407/test-whether-a-glob-has-any-matches-in-bash

반응형