이 스크립트는 다음과 같습니다.
a=2
[[ "$a" -eq 2 ]] && echo yes1
[[ $a -eq 2 ]] && echo yes2
[[ a -eq 2 ]] && echo yes3
[[ "a" -eq 2 ]] && echo yes4
해당되지 않음스프린트(그리고 [[ 가 없는 다른 것들도 있습니다).
마지막 두 번의 "예 테스트"가 실패했습니다.금연 건강 증진 협회(BusyBox 회색). 내가 예상했던 대로.
그러나 매우 예상치 못한 일입니다.
이는 산술 "-eq"(및 기타 산술)를 사용할 때 발생합니다.
4개를 모두 인쇄하는 것은케시,크쉬 93,케시,므케시,세게 때리다그리고다루기 힘든.
질문됨
이것은 ( ) 와 같은 레이블에 적용된 "산술 확장"의 자연스러운 부작용입니까 a
?
(아무것도 없는데 계속 걸어가자?)
( )를 인용할 때 a
여전히 변수로 확장 해야 합니까 "a"
?
아직 조사하지 않은 곳에 이 내용이 기록되어 있습니까?
아니면 단순한(아주 오래된) 실수인가요?
편집하다
실제로 생각해 보려면 다음을 확인하세요.
a=2; b=2
[[ "$a" -eq "$b" ]] && echo yes1
[[ $a -eq "$b" ]] && echo yes2
[[ a -eq "$b" ]] && echo yes3
[[ "a" -eq "$b" ]] && echo yes4
[[ "$a" -eq "$b" && "$a" == "$b" ]] && echo new1
[[ $a -eq "$b" && $a == "$b" ]] && echo new2
[[ a -eq "$b" && a == "$b" ]] && echo new3
[[ "a" -eq "$b" && "a" == "$b" ]] && echo new4
new1 및 new2를 제외한 모든 작업. var a는 new3 및 4에서 확장되지 않습니다.
이는 계산 중에 셸이 모드(산술 - 문자열)를 전환한다는 의미입니다.
이것은 나에게 분명하지 않은 것 같습니다. 적어도 내 생각에는 그렇지 않다.
Ash는 다른 방식으로 이를 수행합니다. 또한 오류를 보고합니다.
결론적으로:
나는 정답을 모른다. 그러나 나는 이것이 (개발자에게) 테스트가 작동해야 하는 잘 알려진 방식이라고 생각합니다(정확히 동일한 방식으로 수행되는 수많은 쉘을 보면). 사실을 알고 적응해야 합니다.
-eq
숫자의 경우 적용될 수 있는 유일한 "조건식"은 다음 과 같습니다 .
exp1 -eq exp2
true if exp1 is numerically equal to exp2.
-eq
이것은 "산술 표현"의 양면을 만듭니다.
==
적용할 수 있는 유일한 "조건식"은 다음과 같습니다 .
string == pattern
true if string matches pattern. ....
이렇게 하면 왼쪽이 문자열(확장 없음?)로 되고 오른쪽이 패턴이 됩니다(이러한 복잡성을 피하기 위해 모든 것이 오른쪽에서 참조되므로 실제로 내가 생각해낸 테스트에서는 작동하지 않습니다. 따라서 오른쪽이 기본값입니다. (인용)도 문자열입니다(여기서는 산술 확장이 없습니다).
그런데 어쩌면 생각보다 더 헷갈릴 수도 있겠네요 :-)
어떻게 말해요?
답변1
에서 man ksh
:
산술 표현식은 C 언어와 동일한 구문, 우선 순위 및 표현식 연관성을 사용합니다. 부동 소수점 수량에 사용할 수 있는 모든 C 언어 연산자를 사용할 수 있습니다. 매개변수 확장 구문을 사용하지 않고도 산술 표현식에서 변수를 이름으로 참조할 수 있습니다. 변수가 참조되면 해당 값은 산술 표현식으로 평가됩니다.
조건식은
[[
속성을 테스트하기 위해 복합 명령과 함께 사용됩니다.문서비교하고끈. 와 사이의 단어에서는[[
필드 분할 및 파일 이름 생성이 수행 되지 않습니다]]
. 각 표현식은 다음 단항 또는 이항 표현식 중 하나 이상으로 구성될 수 있습니다.다음과 같은 오래된 산술 비교도 허용됩니다.
exp1
-eq
exp2
- 실제로 만약에
exp1
동일한exp2
.
exp1
-ne
exp2
- 실제로 만약에
exp1
같지 않음exp2
.
exp1
-lt
exp2
- 실제로 만약에
exp1
미만exp2
.
exp1
-gt
exp2
- 실제로 만약에
exp1
그 이상exp2
.
exp1
-le
exp2
- 실제로 만약에
exp1
보다 작거나 같음exp2
.
exp1
-ge
exp2
- 실제로 만약에
exp1
보다 크거나 같음exp2
.
거기에 있는 문서는 산술에 대한 언급이 일관됩니다.표현걱정이 되고,(매우 조심스러운 모습을 볼 수 있습니다)정의에 대한 모순을 피하십시오[[
복합 명령 ]]
~에 대한문자열 비교명시적으로또한 허용일부쓸모없는 산술 비교같은 맥락에서.
에서 man bash
:
[[
expression
]]
- 상태를 반환
0
하거나1
조건식 평가에 따라 달라집니다.expression
. 표현식은 아래 설명된 기본 색상으로 구성됩니다...[[
와 사이의 단어에 대해서는 단어 분리 및 경로 이름 확장이 수행되지 않습니다]]
.~
물결표 확장,${
매개변수}
및$
변수 확장,$((
산술 확장))
,$(
명령 대체)
,<(
프로세스 대체)
및 인용 제거가 수행됩니다. 기본 연산자로 인식되려면 따옴표를 풀어야 하는"\'
등의 조건부 연산자 ...-f
ㅏ바꾸다다음 형식의 명령문으로 할당할 수 있습니다.
name
=
[value]
만약에
value
지정하지 않으면 변수에 빈 문자열이 할당됩니다. 모든 값은~
물결표 확장,${
매개변수}
및$
변수 확장,$(
명령 대체)
,$((
산술 확장))
및"\'
따옴표 제거를 거칩니다....if바꾸다가지고 있다정수 속성설정을 한 다음value
$((
산술 표현식 으로 평가됩니다))
.$((
...
))
확장 프로그램이 사용되지 않았습니다...쉘은 산술을 허용합니다
expressions
경우에 따라 평가하려면... 평가는 고정 너비 정수로 수행되며 오버플로는 확인되지 않지만 0으로 나누는 것이 포착되어 오류로 표시됩니다. 연산자와 그 우선순위, 결합성, 값은 C언어와 동일합니다.쉘 변수는 피연산자로 허용됩니다. 매개변수 확장은 표현식 평가 전에 수행됩니다. 안에
expression
, 쉘 변수는 매개변수 확장 구문을 사용하지 않고도 이름으로 참조될 수도 있습니다. 변수의 값은 산술적으로 평가됩니다.expression
참조될 때 또는 정수 속성이 할당된 변수에declare -i
값이 할당될 때... 쉘 변수는 표현식에서 사용하기 위해 정수 속성을 켤 필요가 없습니다.가정 어구
expressions
사용된[[
복합 명령그리고test
그리고[
내장 명령파일 속성을 테스트하고 문자열 및 산술 비교를 수행합니다...
arg1
OP
arg2
OP
-eq
,-ne
,-lt
,-le
,-gt
또는 중 하나 입니다-ge
. 이러한 산술 이진 연산자는 다음과 같은 경우 true를 반환합니다.arg1
같음, 같지 않음, 작음, 작거나 같음, 크거나 크거나 같음arg2
, 각각.arg1
그리고arg2
양수 또는 음수일 수 있습니다.
이러한 모든 배경을 고려할 때, 문서에 명시적으로 가능성이 명시되어 있지 않더라도 관찰한 동작이 의미가 있다고 생각합니다. 문서에는 특별한 취급이 명시되어 있습니다.매개변수그리고정수 속성, 그리고 차이점을 명확하게 표현합니다.복합 명령그리고내장 명령.
[[
비교적통사론task와 같은 의미name
=
value
예통사론또는case
word
in...
예통사론. 그러나 test
합계는 [
이것이 아니라 매개변수가 있는 별도의 프로세스입니다. 차이점을 실제로 이해하는 가장 좋은 방법은 쉘 오류 출력을 보는 것입니다.
set '[[ \\ -eq 0 ]]' '[ \\ -eq 0 ]'
for sh in bash ksh
do for exp
do "$sh" -c "$1||$2"
set "$2" "$1"
done; done
bash: [[: \: syntax error: operand expected (error token is "\")
bash: line 0: [: \: integer expression expected
bash: line 0: [: \: integer expression expected
bash: [[: \: syntax error: operand expected (error token is "\")
ksh: \: arithmetic syntax error
ksh: [: \: arithmetic syntax error
ksh: \: arithmetic syntax error
두 셸은 예외를 다르게 처리하지만 두 셸 간의 차이의 근본 원인은 매우 유사합니다.
bash
[[ \\
사례를 직접 호출하세요.문법 오류- 예를 들어 같은 방식으로 존재하지 않는 파일에서 리디렉션하는 경우 - 해당 지점에서 시작되지만(내 생각엔 틀렸어)||
or 표현식의 반대쪽을 평가합니다 .bash
하다[[
표현을 해보세요명령 이름오류 출력에 있지만 command 에서처럼 호출한 줄 번호에 대해서는 설명하지 않습니다[
. 기대했던 정보를 받지 못했다고bash
불평하기[
정수 표현식하지만[[
실제로는 논쟁이 필요하지 않고 결코 그럴 필요가 없기 때문에 그런 식으로 불평할 필요는 없습니다.예상되는확장 자체로 구문 분석되면 무엇이든 가능합니다.ksh
구문 오류가 있으면 완전히 중지하고[[
전혀 신경 쓰지 마십시오.[
둘 다에 대해 동일한 오류 메시지를 기록하지만[
하나가 할당되어 있습니다.명령 이름거기[[
는ksh
.[
명령줄이 성공적으로 구문 분석되고 확장이 발생한 후에 만 호출됩니다. 자체 작은getopts
루틴을 실행하고 자체 루틴arg[0c]
과 나머지 루틴을 가져오지만[[
다시 기본 쉘 구문으로 처리됩니다.
문서가 이러한 용어를 사용하기 때문에 bash
버전보다 약간 덜 명확하다고 생각합니다.ksh
arg[12]
대신에expression
[[
정수 비교에 관해서는 , [
, 및 test
가 그 순간에 모두 함께 클러스터되어 있고 후자의 두 개가 실제로 필요하기 때문에 그렇게 된 것 같습니다.논쟁전자는 하나만 받았습니다.expression
.
어쨌든 정수 비교는 다음에서 수행됩니다.통사론상황에 따라 기본적으로 유효한 수학 연산을 수행할 수 있습니다.expression
:
m=5+5 a[m]=10
[[ m -eq 10 ]] &&
[[ m++ -eq 10 ]] &&
[[ m-- -gt 10 ]] &&
[[ ${a[m]} == 10 ]] &&
echo "math evals"
math evals
답변2
이는 잘 문서화되어 있습니다 bash
. 예를 들면 다음과 같습니다.
[[ expression ]]
[...] Word splitting and pathname expansion
are not performed on the words between the [[ and ]];
tilde expansion, parameter and variable expansion,
arithmetic expansion, command substitution, process
substitution, and quote removal are performed.
또는 zsh
:
CONDITIONAL EXPRESSIONS
A conditional expression is used with the [[ compound
command to test...
[...]
In the forms which do numeric comparison,
the expressions exp undergo arithmetic
expansion as if they were enclosed in $((...)).
답변3
[[
POSIX 기능이 아니라 ksh88
기능입니다.
무슨 일이 일어나고 있는지 알고 싶다면 ksh 문서를 읽어야 합니다.
이 기능에 대해 배우고 싶으신 것 같으니 , 이것이 내장된 명령이 아니라 쉘 구문의 일부이므로 명령과는 완전히 다른 기반 으로 작동한다는 [[
점을 알아야 합니다 .[[
[
test
따라서 예를 들어 [[ $var == *test? ]]
오른쪽의 패턴을 따옴표로 묶을 필요가 없습니다.