programing

Bash에서 글로벌에 일치하는 항목이 있는지 테스트

starjava 2023. 5. 12. 20:09
반응형

Bash에서 글로벌에 일치하는 항목이 있는지 테스트

단일 파일이 있는지 확인하려면 다음을 사용하여 테스트할 수 있습니다.test -e filename또는[ -e filename ].

만약 내가 글로벌을 가지고 있고 이름이 글로벌과 일치하는 파일이 있는지 알고 싶습니다.글로벌은 0개의 파일(이 경우 아무것도 할 필요가 없음)과 일치하거나 1개 이상의 파일(이 경우 무언가를 수행해야 함)과 일치할 수 있습니다. 글로벌에할 수 있을까요? (몇 항목이, 한 의 일치 항목으로 할 수 것입니다.)if문장과 루프가 없습니다(단순히 읽을 수 있기 때문입니다).

(test -e glob*글로벌이 둘 이상의 파일과 일치하는 경우 실패합니다.)

Bash 관련 솔루션:

compgen -G "<glob-pattern>"

패턴을 피하지 않으면 일치 항목으로 미리 확장됩니다.

종료 상태:

  • 1: 일치하지 않는 경우,
  • '하나 이상의 일치'의 경우 0

stdout글로벌과 일치하는 파일 목록입니다.저는 이것이 간결함과 잠재적인 부작용을 최소화하는 측면에서 가장 좋은 선택이라고 생각합니다.

예:

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

nullglob 쉘 옵션은 실제로 배시즘입니다.

nullglobal 상태의 지루한 저장 및 복원이 필요하지 않도록 Global을 확장하는 하위 셸 내에서만 설정합니다.

if test -n "$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi

휴대성을 향상시키고 보다 유연한 글러브링을 위해 다음 찾기를 사용합니다.

if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi

검색 기준과 일치하는 첫 번째 파일을 찾는 즉시 찾기가 종료되도록 기본 암묵적 -print 작업 대신 명시적 -print -quit 작업이 검색에 사용됩니다.많은 파일이 일치하는 경우 이는 다음보다 훨씬 더 빨리 실행되어야 합니다.echo glob*또는ls glob*또한 확장된 명령줄이 과도하게 채워질 가능성을 방지합니다(일부 셸의 경우 4K 길이 제한이 있음).

find가 오버킬처럼 느껴지고 일치할 가능성이 있는 파일 가 적으면 stat:

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi

좋아해요

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

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

이는 읽기 쉽고 효율적입니다(많은 파일이 있는 경우는 제외).
가장 큰 단점은 보기보다 훨씬 미묘하다는 것이고, 가끔 긴 코멘트를 덧붙여야 할 때가 있습니다.
만약 일치하는 것이 있다면,"glob*"는 셸에 항목은 셸에의확모일든항에전치다달니됩목이고장으로 됩니다.exists()첫 번째 것은 확인하고 나머지는 무시합니다.
상대가 없다면,"glob*"으로 전달됨exists()그리고 그곳에도 존재하지 않는 것으로 밝혀졌습니다.

편집: 잘못된 긍정이 있을 수 있습니다. 주석을 참조하십시오.

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

만약 당신이 글로벌 실패 세트를 가지고 있다면, 당신은 이 미친 것을 사용할 수 있습니다 (당신은 정말 해서는 안 됩니다).

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

미쿠의 생각을 바탕으로 미쿠의 대답을 다소 단순화하기 위해:

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

파일을 반복하기 전에 파일이 있는지 테스트하려면 다음 패턴을 사용할 수 있습니다.

  for F in glob*; do
    if [[ ! -f $F ]]; then break; fi
    
    ...

  done

glob이 일치하지 않으면 $F는 확장되지 않은 glob(이 경우 glob*)이 되고 동일한 이름의 파일이 존재하지 않으면 나머지 루프를 건너뜁니다.

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]}" ]

이 방법의 장점은 전역 작업을 반복하지 않고 작업할 파일 목록을 얻을 수 있다는 것입니다.

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

설명.

▁와 일치하지 않을 glob*,그리고나서$1을 합니다.'glob*' 시험은-f "$1"사실이 아닐 것이다 왜냐하면glob*파일이 없습니다.

이것이 대안보다 나은 이유

이것은 Shand 파생물인 KornShell과 Bash와 함께 작동합니다.하위 셸을 만들지 않습니다. $(..)그리고.`...`명령은 하위 셸을 생성합니다. 명령은 프로세스를 포크하므로 이 솔루션보다 느립니다.

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왜냐하면 우리는 더 많은 경우와 더 정확하게 구별할 수 있기 때문입니다.

" 드카드는하사수있다니습할용와나만일▁다▁only▁with▁one▁work▁it" 하나만 사용할 수 있습니다.*.

이 혐오는 효과가 있는 것 같습니다.

#!/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 명령에서 비어 있지 않은 출력은 글로벌이 일치한다는 것을 나타냅니다.

확장된 글러브를 위한 솔루션(extglob Bash:(으)로 표시:

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

하나 이상의 일치 항목이 있는 경우 종료 상태는 0이고, 일치 항목이 없는 경우 0이 아닙니다(2).표준 출력에는 일치하는 파일(및 따옴표로 묶은 공백이 포함된 파일 이름)이 줄로 구분된 새 목록이 포함됩니다.

또는 약간 다릅니다.

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

ls- 기반 솔루션: 아마도 더 빠름(측정되지 않음), 출력에 공백이 따옴표로 묶이지 않은 파일 이름, 일치하는 항목이 없을 때는 코드 1을 종료합니다(2:vmx: 아님).

사용 예:

일치 항목 없음:

$ 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

하나 이상의 일치:

$ 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 코드 동작 ( behavior)-U효율성을 위해, 그리고-1출력 제어용).
  • 을 사용하지 .extglob현재 셸에서(종종 원하지 않음).
  • 를 합니다.$접두사를 붙여 다음과 같이 합니다.\n확장된 글로벌 패턴이 다음과 다른 라인에 있도록 해석됩니다.shopt -s extglob그렇지 않으면 확장된 글로벌 패턴은 구문 오류가 될 것입니다!

참고 1: 저는 이 솔루션을 위해 노력했습니다. 왜냐하면compgen -G "<glob-pattern>"다른 답변에서 제안된 접근 방식은 브레이스 확장과 함께 원활하게 작동하지 않는 것 같습니다. 하지만 저는 좀 더 발전된 글로빙 기능이 필요했습니다.

참고 2: 확장 글로벌 구문에 대한 사랑스러운 리소스: extglob

둘다요.nullglob그리고.compgen일부 배시 셸에서만 유용합니다.

대부분의 셸에서 작동하는 (비재귀적) 솔루션은 다음과 같습니다.

set -- ./glob*                  # or /path/dir/glob*
[ -f "$1" ] || shift            # remove the glob if present.
if    [ "$#" -lt 1 ]
then  echo "at least one file found"
fi

파일이 존재하는 경우 파일에 대한 작업을 수행할 수 있다고 가정합니다.

mapfile -t exists < <(find "$dirName" -type f -iname '*.zip'); [[ ${#exists} -ne 0 ]] && { echo "Zip files found" ; } || { echo "Zip files not found" ; }

그런 다음 파일을 사용하여 작업을 수행해야 할 경우 기존 배열을 순환할 수 있습니다.

(ls glob* &>/dev/null && echo Files found) || echo No file found
if ls -d $glob > /dev/null 2>&1; then
  echo Found.
else
  echo Not found.
fi

일치하는 항목이 많거나 파일 액세스 속도가 느릴 경우 시간이 많이 걸릴 수 있습니다.

ls | grep -q "glob.*"

가장 효율적인 솔루션은 아니지만(디렉토리에 파일이 많이 있는 경우 속도가 느릴 수 있음) 간단하고 읽기 쉬우며 정규식이 일반 Bashglob 패턴보다 강력하다는 장점이 있습니다.

[ `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

반응형