쉘 글로브의 XOR

쉘 글로브의 XOR

최근 내 호스팅 공급자가 public_html내가 모르는 사이에 내 디렉터리 이름을 변경했기 때문에 이 변수 ​​선언은 더 이상 유효하지 않습니다.wwwweb_application_root="${HOME}/public_html"

public_html"해당 호스팅 환경에서 반드시 필요한 것은 아니지만 유사한 향후 상황을 위해 Bash에게 XOR 기반 변수를 생성하도록 지시하고 싶습니다 www.

가능하다면 어떻게 가능합니까?

답변1

내 생각엔 네가 더 잘할 수 없을 것 같아

web_application_root="${HOME}/public_html"
if [ ! -d "$web_application_root" ] ; then
   web_application_root="${HOME}/www"
fi

다양한 형태로. 예를 들어

for loc in "${HOME}/public_html" "${HOME}/www" ; do
   web_application_root=$loc
   [ -d "$loc" ] && break
done

본질적으로 존재하는 첫 번째 디렉토리를 찾아서 사용하십시오.

답변2

나는 여기 스레드의 질문에 대답하려고 노력할 것입니다.

*.txt와일드카드는 일치하는 파일 경로 목록과 같이 와일드카드 패턴을 확장한 것입니다 .

files=(~/*.txt)

~이름이 배열의 개별 요소로 끝나는 숨김되지 않은 파일 목록을 할당합니다 (glob이 어떤 파일과도 일치하지 않을 때 동작은 쉘마다 다릅니다)..txt$files

XOR(A, B)Aor 가 참 이면 참 B이지만 둘 다 참은 아니므로 다음과 같습니다.AND(OR(A, B), NOT(AND(A, B)))

나는 XORglob/와일드카드 연산자가 있는 쉘을 모르지만 여러 쉘 에는 하나 와 OR가 있습니다 NOT. ).ANDAND(X, Y)NOT(OR(NOT(X), NOT(Y)))XORAND-NOTAND AND-NOT(X, NOT(Y))

이 공식을 결합하면 다음과 같은 결과를 얻습니다.

XOR(A, B) == NOT(OR(NOT(OR(A, B)), NOT(NOT(NOT(OR(NOT(A), NOT(B)))))))

이를 다음과 같이 단순화할 수 있습니다(이중 부정 제거).

XOR(A, B) == NOT(OR(NOT(OR(A, B)), NOT(OR(NOT(A), NOT(B)))))

ksh또는 bash -o extglob(또는 ) 전역 변수 로 변환되면 zsh -o kshglob다음과 같습니다.

!(!(A|B)|!(!(A)|!(B)))

또는 zsh -o extendedglob글로브를 사용하십시오:

^(^(A|B)|^(^A|^B))

또는 다음을 사용하십시오 AND-NOT.

XOR(A, B) == AND-NOT(OR(A, B), NOT(NOT(AND-NOT(A, NOT(B)))))

다음과 같이 단순화할 수 있습니다.

XOR(A, B) == AND-NOT(OR(A, B), AND-NOT(A, NOT(B)))

일단 zsh -o extendedglobglob으로 변환되면:

(A|B)~(A~^B)

foo*예를 들어, 일치 하지만 둘 다 일치하지 않는 파일을 찾으려면 *.txt다음을 수행합니다.

그리고 ksh또는 bash -o extglob(또는 zsh -o kshglob):

files=(!(!(foo*|*.txt)|!(!(foo*)|!(*.txt))))

또는 다음을 사용하여 zsh -o extendedglob:

files=(^(^(foo*|*.txt)|^(^foo*|^*.txt)))

또는:

files=((foo*|*.txt)~(foo*~^*.txt))

POSIX 쉘에는 이진(비트 단위) XOR 산술 연산자가 있습니다. 그대로 $(( 1 ^ 2 ))로 확장됩니다 .3XOR(0b01, 0b10)

xor따라서 두 셸 코드의 평가 중 하나만 true를 반환하는 경우 true를 반환하는 함수를 다음과 같이 정의할 수 있습니다 .

xor() {
  eval "$1"; s1=$((!$?))
  eval "$2"; s2=$((!$?))
  [ "$((s1 ^ s2))" -ne 0 ]
}
match() {
  case $1 in
    ($2) true;;
    (*)  false;;
  esac
}
for file in *; do
  if
    xor 'match "$file" "foo*"' \
        'match "$file" "*.txt"' &&
  then
    printf '%s\n' "$file"
  fi
done

관련 정보