bash에서 디렉토리 경로를 찾을 때 정규식을 전달하는 방법은 무엇입니까?


14

나는 디렉토리가 이름 anaconda또는 miniconda내 사용자 인지 확인하기 위해 작은 bash 스크립트를 작성했습니다 $HOME. 그러나 miniconda2내 집 에서 디렉토리를 찾지 못했습니다 .

이 문제를 어떻게 해결할 수 있습니까?

if [ -d "$HOME"/"(ana|mini)conda[0-9]?" ]; then
    echo "miniconda directory is found in your $HOME"
else
    echo "anaconda/miniconda is not found in your $HOME"
fi

추신 : 내가 가지고 있다면 [ -d "$HOME"/miniconda2 ]; thenminiconda2 디렉토리를 찾아서 오류가 부분에 있다고 생각합니다."(ana|mini)conda[0-9]?"

스크립트가 일반적이기를 원합니다. 나에게는 miniconda2이지만 다른 사용자에게는 anaconda2, miniconda3 등일 수 있습니다.


다른 사용자는 anaconda_2 또는 -2 또는 -may2019를 사용할 수 있습니다. xxxconda *가 더 나을까요?
WinEunuuchs2Unix

2
Bash 파일 이름 확장은 정규 표현식이 아닌 glob 표현식을 사용합니다.
Peter Cordes

답변:


13

멋지게하기에는 놀랍도록 까다로운 일입니다.

기본적 -d으로 정규 표현식을 사용하여 파일 이름을 일치시킬 수있는 경우에도 단일 인수 만 테스트합니다.

한 가지 방법은 문제를 해결하고 디렉토리에 대한 정규식 일치를 테스트하는 대신 디렉토리를 정규식 일치에 대해 테스트하는 것입니다. 즉, 간단한 쉘 글로브 를 사용하여 모든 디렉토리를 반복하고 $HOME정규식에 대해 각각 테스트하고 일치하는 것을 깨고 마지막으로 BASH_REMATCH배열이 비어 있지 않은지 테스트합니다 .

#!/bin/bash

for d in "$HOME"/*/; do
  if [[ $d =~ (ana|mini)conda[0-9]? ]]; then
    break;
  fi
done

if ((${#BASH_REMATCH[@]} > 0)); then
    echo "anaconda/miniconda directory is found in your $HOME"
  else
    echo "anaconda/miniconda is not found in your $HOME"
fi

다른 방법은 정규식 대신 확장 쉘 글로브를 사용하고 배열에서 글로브 일치를 캡처하는 것입니다. 그런 다음 배열이 비어 있지 않은지 테스트하십시오.

#!/bin/bash

shopt -s extglob nullglob

dirs=( "$HOME"/@(ana|mini)conda?([0-9])/ )

if (( ${#dirs[@]} > 0 )); then
  echo "anaconda/miniconda directory is found in your $HOME"
else
  echo "anaconda/miniconda is not found in your $HOME"
fi

후행 /은 디렉토리 만 일치되도록합니다. 은 nullglob제로 경기의 경우에 타의 추종을 불허하는 문자열을 반환에서 쉘을 방지 할 수 있습니다.


재귀를 수행하려면 globstar셸 옵션 ( shopt -s globstar)을 설정 한 다음 각각 :-

  • (정규 버전) : for d in "$HOME"/**/; do

  • (확장 글로브 버전) : dirs=( "$HOME"/**/@(ana|mini)conda?([0-9])/ )


1
나는 배열 경로를 갔다. ?([0-9])대신 사용할 수 있습니다 @(|[0-9])- ?(...)정규 표현식 ?수량 자 와 같은 0 또는 1과 일치합니다 .
glenn jackman

2
extglob도 필요하지 않습니다. 중괄호 확장을 사용하면 (가능한 모든 일치하는 이름이 생성됨) :~/{ana,mini}conda{0..9}*/
xenoid

가 개최되도록하거나 이러한 솔루션의 편집에 어쨌든 거기 에도 경우 mini또는 anaconda설치되어 $HOME/sub-directories? 예를 들어$HOME/sub-dir1/sub-dir2/miniconda2
Jenny

1
globstar
@Jenny

1
일반적인 접근 방식을 설명하기위한 목적으로 그대로 난 그냥 OP의 정규식을했다 - @terdon 그래 정말 일치하도록 "오른쪽"일이 무엇의 토끼 구멍 아래로 가고 싶지 않았다
steeldriver

9

실제로 이미 언급했듯이 이것은 까다 롭습니다. 내 접근 방식은 다음과 같습니다.

  • 사용 find및 해당 정규식 기능을 사용 하여 해당 디렉토리를 찾으십시오.
  • 하자 find를 인쇄 x발견 된 각 디렉토리
  • xes를 문자열로 저장
  • 문자열이 비어 있지 않으면 디렉토리 중 하나가 발견 된 것입니다.

그러므로:

xString=$(find $HOME -maxdepth 1 \
                     -type d \
                     -regextype egrep \
                     -regex "$HOME/(ana|mini)conda[0-9]?" \
                     -printf 'x');
if [ -n "$xString" ]; then
    echo "found one of the directories";
else
    echo "no match.";
fi

설명:

  • find $HOME -maxdepth 1아래에서 모든 것을 찾지 $HOME 만 검색을 한 수준으로 제한합니다 (즉, 하위 디렉토리로 재귀하지 않음).
  • -type d검색을 directories 로만 제한
  • -regextype egrep우리가 다루는 정규식의find 유형을 알려줍니다 . 이것은 필요 하고 다소 특별하고 기본적으로 인식하지 못 하기 때문에 필요 합니다.[0-9]?(…|…)find
  • -regex "$HOME/(ana|mini)conda[0-9]?"우리가 찾고자 하는 실제 정규식 입니다.
  • -printf 'x' 이전 조건을 만족시키는 x모든 것을 인쇄합니다 .

일치하는 경우. -bash: -regex: command not found found one of the directories
Jenny

안녕하세요 PerlDuck : 감사합니다. 좋은 답변도 있습니다. 그러나 오류가 발생합니다. printf예를 들어 스크립트를 실행할 때 정상적으로 실행되지만 일치하는 항목이 없을 때 printf 명령을 찾지 못하지만 인쇄 할 것이 없기 때문에 출력이라고 생각합니다. -bash: -printf: command not found no match.
Jenny

3
@Jenny 당신은 그것을 위해 잘 작동하기 때문에 그것을 복사 할 때 오타를했을 수 있습니다. -printf명령이 아니라에 대한 인수 find입니다. 이것이 이전 줄의 끝에서 백 슬래시가하는 일입니다.
wjandrea

1
모호성을 계속 감지 -quit하지 않으 려면 찾은 경로를 인쇄 한 후 제안 합니다.
Peter Cordes

그리고 실제 경로를 인쇄하지 않으시겠습니까? 당신은 이미 그것을 가지고 있으므로 그것을 버리고 x대신 사용 하는 것이 부끄러운 것 같습니다 :foundDir=$(find $HOME -maxdepth 1 -type d -regextype egrep -regex "$HOME/(ana|mini)conda[0-9]?" -print -quit); echo "found $foundDir"
terdon

2

테스트하려는 디렉토리 이름 목록을 반복하여 해당 디렉토리 이름 중 하나가 존재하는 경우 조치를 취할 수 있습니다.

a=0
for i in {ana,mini}conda{,2}; do
  if [ -d "$i" ]; then
    unset a
    break
  fi
done
echo "anaconda/miniconda directory is ${a+not }found in your $HOME"

이 솔루션은 분명히 완전한 정규 표현식을 허용하지 않지만 쉘 글 로빙 및 가새 확장은 적어도 당신이 보여준 경우와 같습니다. 하나의 디렉토리가 존재하면 루프가 종료되고 이전에 설정된 변수를 설정 해제합니다 a. 다음 echo행에서 매개 변수 확장 은 설정되어 ${a+not }있으면 a(= dir을 찾을 수 없음) 그렇지 않은 경우 "not"으로 확장 됩니다 .


1

가능한 해결 방법은 아래 표시된 것처럼 miniconda와 anaconda를 개별적으로 검색하는 것입니다.

if [ -d "$HOME"/miniconda* ] || [ -d "$HOME"/anaconda* ]; then
    echo "miniconda directory is found in your $HOME"
else
    echo "anaconda/miniconda is not found in your $HOME"
fi

그러나 누군가 제안이 있으면 디렉토리를 검색 할 때 정규 표현식을 전달할 수없는 이유를 알고 싶습니다.


2
나는 이것을 높이 평가했다. 그러나 사용자가 하나 이상의 일치하는 디렉토리 (예 : miniconda AND miniconda2)를 가지고 있다면 깨질 것이라고 깨달았다
steeldriver

@steeldriver : "사용자가 하나 이상의 일치하는 디렉토리를 가지고 있다면 깨질 것입니다."예, 사실입니다. 해결 방법에 대한 제안이 있습니까?
Jenny

@Jenny steeldriver의 답변과 같은 배열을 사용하십시오. shopt -s nullglob; dirs=( "$HOME"/miniconda* "$HOME"/anaconda* ); if (( ${#dirs[@]} > 0 )); then ...
wjandrea

당신이 바꿀 경우 ] || [-o그것을 모두 디렉토리 globs와 동일한 테스트를 찾았다대로 두 디렉토리가 발견 될 경우 적어도 중단해서는 안된다.
피닉스

@steeldriver와 Jenny : 하나를 선택하는 대신 모호성을 없애고 싶을 수도 있습니다 . 사용자가 잘못된 디렉토리를 선택하는 대신 디렉토리를 지정하도록하십시오. (예 : 자동 감지 코드를 실행하는 대신 디렉토리 이름을 설정하도록 스크립트를 편집하십시오.)
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.