bash [[]] 명령 내부의 자동 변수 확장


13

에서 변수를 역 참조 할 때는 부호 bash를 사용해야 $합니다. 그럼에도 불구하고 다음이 제대로 작동하는 것 같습니다.

x=5
[[ x -gt 2 ]]

아무도 이것을 설명 할 수 있습니까?

편집 : (추가 정보)

내 말은 [[]] 명령이 $ 기호없이 변수 x를 역 참조하는 방법과 이유입니다. 그리고 그렇습니다. x = 1이면, 문장은 거짓으로 평가됩니다 (반환 상태 1).


2
"잘 작동한다"는 것은 무엇을 의미합니까? 그리고 당신이 x=1다음에 평가가 변경 [[ x -gt 2]]됩니까?
nohillside

내 말은 : 어떻게 그리고 왜 [[]] 명령이 $ 부호없이 변수 x를 역 참조 하는가. 그리고 네, x = 1이면, 그 진술은 거짓입니다 (반환 상태 1)
Guest

답변:


9

그 이유는 -eq인수의 산술 평가를 강제하기 때문입니다 .

산술 연산자 : -eq, -gt, -lt, -ge, -le-ne돌며 [[ ]](KSH에서 zsh을 배시) 자동 C 언어로 변수 이름을 확장 수단 선두 위해 필요하지 $.

  • 확인을 위해 bash 소스 코드를 살펴 봐야합니다. 매뉴얼은 직접 확인 하지 않습니다 .

    test.c산술 연산자의 처리 내부 에는이 함수가 포함됩니다.

    arithcomp (s, t, op, flags)

    어디 st두 피연산자입니다. 피연산자는이 함수로 전달됩니다.

    l = evalexp (s, &expok);
    r = evalexp (t, &expok);

    이 함수 evalexp는 내부 expr.c에 정의되어 있으며이 헤더는 다음과 같습니다.

    /* expr.c -- arithmetic expression evaluation. */

    그래서, 산술 연산자의 양쪽은 (직접적으로) 산술 표현 평가에 빠지게됩니다. 직접, 엉덩이도없고, if도 없습니다.


실제로,

 $ x=3

이 두 가지 모두 실패합니다.

 $ [[ x = 4 ]] && echo yes || echo no
 no

 $ [[ x = 3 ]] && echo yes || echo no
 no

어느 것이 정확 x하고 확장 x되지 않고 숫자 와 같지 않습니다.

하나:

 $ [[ x -eq 3 ]] && echo yes || echo no
 yes

 $ [[ x -eq 4 ]] && echo yes || echo no
 no

이름 x이 붙은 변수 는 $없이 확장됩니다.

이것은 […]zsh 또는 bash (ksh에서)에서 발생하지 않습니다 .


그것은 내부에서 일어나는 것과 동일합니다 $((…)):

 $ echo $(( x + 7 ))
 10

그리고 이것이 (매우) 재귀 적이라는 것을 이해하십시오 (대시 및 야쉬 제외).

 $ a=b b=c c=d d=e e=f f=3
 $ echo "$(( a + 7 ))" 
 10

😮

그리고 매우 위험합니다 :

 $ x='a[$(date -u)]'
 $ [[ x -eq 3 ]] && echo yes || echo no
 bash: Tue Dec  3 23:18:19 UTC 2018: syntax error in expression (error token is "Dec  3 23:18:19 UTC 2018")

구문 오류는 쉽게 피할 수 있습니다.

 $ a=3; x='a[$(date -u >/dev/tty; echo 0)]'

 $ [[ x -eq 3 ]] && echo yes || echo no
 Tue Dec  4 09:02:06 UTC 2018
 yes

말대로 : 입력을 소독하십시오

 $ [[ ${x//[^0-9]} -eq 3 ]] && echo yes || echo no
 no

😮의 끝


(오래된) 외부 /usr/bin/test(내장되지 않음 test)와 더 오래되고 외부 expr는 모두 표현식정수 (및 분명히 십진 정수 만)를 확장하지 않습니다 .

 $ /usr/bin/test "x" -eq 3
 /usr/bin/test: invalid integer x

 $ expr x + 3
 expr: non-integer argument

흥미 롭군 이것이 어떻게 가능한지 말하기는 어렵지 않습니다 - [[키워드, 연산자 및 피연산자는 확장 후가 아니라 명령을 읽을 때 감지됩니다. 따라서 보다 더 현명한 방법으로 [[치료할 수 있습니다 . 그러나 내가 궁금한 점은 복합 명령을 해석하기 위해 bash가 사용하는 논리에 대한 문서를 어디에서 찾을 수 있습니까? 그것은 나에게 분명하게 보이지 않으며 또는 에서 만족스러운 설명을 찾을 수없는 것 같습니다 . -eq[maninfo bash
fra-san

Bash는 내가 찾을 수있는 곳에서는 이것을 문서화하지 않습니다. 이 종류 의 설명 남자의 경우 ksh93이 : 다음 쓸모 산술 비교도 허용됩니다 EXP1 -eq EXP2 . 이 텍스트가 사람 zshbuiltins의 섹션 산술 연산자 오히려 산술 식에 비해 인수 정수 기대합니다 . 이는 일부 인용문이이 인용문에 명시되지 않은 조건에서 테스트 내장에 의해 산술 표현식 으로 취급됨을 확인합니다 . 소스 코드로 확인하겠습니다….…test
Isaac Isaac

7

수치 비교 피연산자는 -eq, -gt, -lt, -ge, -le-ne연산 식으로 수행된다. 약간의 제한이 있지만, 여전히 단일 쉘 단어 여야합니다.

산술 표현식에서 변수 이름의 동작은 셸 산술에 설명되어 있습니다 .

쉘 변수는 피연산자로 허용됩니다. 표현식이 평가되기 전에 매개 변수 확장이 수행됩니다. 표현식 내에서 매개 변수 확장 구문을 사용하지 않고 쉘 변수를 이름으로 참조 할 수도 있습니다. 매개 변수 확장 구문을 사용하지 않고 이름으로 참조 할 때 널이거나 설정되지 않은 쉘 변수는 0으로 평가됩니다.

그리고 또한:

변수의 값은 참조 될 때 산술 표현식으로 평가됩니다

그러나 실제로 숫자 비교에는 산술 연산식이 필요하다는 문서의 일부를 찾을 수 없습니다. 그것은 설명 아니에요 조건부 구축해 에서 [[않으며에서 설명 배쉬 조건식 .

그러나 실험적으로는 위에서 말한 것처럼 작동하는 것 같습니다.

따라서 다음과 같은 것들이 작동합니다.

a=6
[[ a -eq 6 ]] && echo y 
[[ 1+2+3 -eq 6 ]] && echo y
[[ "1 + 2 + 3" -eq 6 ]] && echo y

이것도 (변수의 값이 평가됩니다) :

b='1 + 2 + 3'
[[ b -eq 6 ]] && echo y

그러나 이것은 그렇지 않습니다. [[ .. ]]구문 분석 할 때 단일 쉘 단어 가 아니므로 조건부에서 구문 오류가 있습니다.

[[ 1 + 2 + 3 -eq 6 ]] && echo y

다른 산술 컨텍스트에서는 표현식에 공백이 없어도됩니다. 999대괄호가 인덱스의 산술 표현식을 명확하게 구분하기 때문에을 인쇄합니다 .

a[6]=999; echo ${a[1 + 2 + 3]}

다른 한편으로, =비교는 패턴 일치 이며, 산술 또는 산술 컨텍스트에서 수행 된 자동 변수 확장 (조건부 구성)을 포함하지 않습니다.

경우 ==!=사업자가 사용하는 extglob 쉘 옵션을 사용하는 것처럼, 작업자의 오른쪽에있는 문자열 패턴 매칭에 설명 된 규칙에 따른 패턴에 일치 간주된다. =오퍼레이터는 동일하다 ==.

따라서 문자열이 분명히 다르기 때문에 이것은 거짓입니다.

[[ "1 + 2 + 3" = 6 ]] 

숫자 값이 동일하더라도 다음과 같습니다.

[[ 6 = 06 ]] 

그리고 여기에서도 문자열 ( x6)이 비교됩니다.

x=6
[[ x = 6 ]]

이것은 변수를 확장시킬 것이기 때문에 사실입니다 :

x=6
[[ $x = 6 ]]

숫자 비교가 산술 연산식이라고하는 문서의 일부를 실제로 찾을 수 없습니다. 확인은에 코드 .
Isaac

가장 가까운 것은 arg1 OP arg2args가 양 또는 음의 정수 일 수 있다고 설명하는 것으로, 산술 표현식으로 취급된다는 것을 암시한다고 생각합니다. 혼란스럽게도 0이 될 수 없음을 의미합니다. :)
Barmar

@Barmar, 네, 맞습니다. 그러나 그것은 숫자 비교에도 적용되며 [산술 표현식이 아닙니다. 대신 Bash는 비정 수에 대해 불평합니다.
ilkkachu

@ilkkachu [ 는 외부 명령이며 쉘 변수에 액세스 할 수 없습니다. 종종 내장 명령으로 최적화되지만 여전히 동일하게 동작합니다.
Barmar

@Barmar, 내가 의미하는 것은 "Arg1과 arg2가 양수 또는 음수 일 수있다" 는 문구였다 . 에 나타납니다 배쉬 조건식 , 그 목록은 적용 [으로 단지뿐만 아니라 [[. 와도[ 의 피연산자 -eq그 설명도 적용 그래서 친구들은 / 정수해야합니다. "산술 표현식으로 해석된다"는 의미로 "정수 여야 함"을 사용하는 것은 두 경우 모두에 적용되지 않습니다. (아마도 [당신이 말한 것처럼 보통 명령처럼 행동 했기 때문일 것입니다.)
ilkkachu

1

예, 관측 값이 정확하고 이중 괄호 아래 표현식에서 변수 확장이 수행 [[ ]]되므로 따로 입력 할 필요가 없습니다.$ 변수 이름 앞에 .

bash매뉴얼에 명시되어 있습니다.

[[ 표현 ]]

(...) 단어 분리 및 경로 이름 확장은 [[와]] 사이의 단어에서 수행되지 않습니다. 물결표 확장, 매개 변수 및 변수 확장, 산술 확장, 명령 대체, 프로세스 대체 및 따옴표 제거가 수행됩니다.

이것은 쉘 키워드 (구문)가 아니라 명령 (단일 bash에서는 내장되어 있으며 다른 쉘은 외부를 사용하여 테스트 할 수 있음) [ ]과 같이 단일 브래킷 버전의 경우 [는 아닙니다.


1
답장을 보내 주셔서 감사합니다. 이것은 숫자에 대해서만 작동하는 것 같습니다. x = city [[$ x == city]] $ 부호가 없으면 작동하지 않습니다.
손님

3
여기에 더 많은 것처럼 보입니다 : (x=1; [[ $x = 1 ]]; echo $?)returns 0, (x=1; [[ x = 1 ]]; echo $?)returns 1, 즉 x문자열을 비교할 때 매개 변수 확장이 수행되지 않습니다 . 이 동작은 산술 확장에 의해 트리거되는 산술 평가, 즉에서 발생하는 것처럼 보입니다 (x=1; echo $((x+1))). (산술 평가에 man bash대해서는 "표현식 내에서 매개 변수 확장 구문을 사용하지 않고 쉘 변수를 이름으로 참조 할 수도 있습니다")
fra-san

@ fra-san 실제로, -gt연산자는 숫자를 기대하므로 전체 표현식은 마치 마치 내부처럼 다시 평가되고 (()), 반면 ==문자열은 문자열 일치를 기대하므로 패턴 일치 함수가 트리거됩니다. 소스 코드를 파헤 치지 않았지만 합리적으로 들립니다.
jimmij

[bash에 내장 된 쉘입니다.
Nizam Mohamed

1
@NizamMohamed 그것은 내장되어 있지만 여전히 키워드는 아닙니다.
Kusalananda
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.