오늘 저는 bash 스크립트를 작성하다가 놀라운 것을 발견했습니다. 나는 이것을 최소한의 예로 요약했습니다.
[[ a>b ]]; echo $?
내 이해에 따르면 주위에 공백이 없기 때문에 >
문자열이 비어 있지 않은지 테스트 a>b
하고 오류 코드를 반환해야 합니다 0
. 그러나 위 명령은 1
테스트한 두 bash 버전 모두에서 에코됩니다(자세한 내용은 아래 참조).
또한 이전 "good" 명령을 사용하여 test
테스트했습니다 .
[ a>b ]; echo $?
echo 0
(문자열이 a
비어 있지 않은지 테스트하고 b
현재 작업 디렉토리에 빈 파일을 생성합니다. >b
이는 분명히 리디렉션으로 처리되며 이해할 수 있습니다).
그런 다음 몇 가지 다른 것을 시도했습니다.
[[ b>a ]]; echo $?
에코가 발생0
하고 파일이 생성되지 않습니다.[[ b<a ]]; echo $?
에코가 발생1
하고 파일이 생성되지 않습니다.[[ a<b ]]; echo $?
에코가 발생0
하고 파일이 생성되지 않습니다.[ b>a ]; echo $?
에코0
하고 빈 파일을 만듭니다a
.[ b<a ]; echo $?
누락된 파일에 대한 오류를 보고a
하고1
해당 오류로 인해 에코됩니다.[ a<b ]; echo $?
누락된 파일에 대한 오류를 보고b
하고1
해당 오류로 인해 에코됩니다.[[ a=b ]]; echo $?
예상대로0
문자열이 비어 있지 않은지 테스트하기 때문에 에코됩니다 .a=b
[ a=b ]; echo $?
0
같은 이유로 에코.[[ a==b ]]; echo $?
0
같은 이유로 에코.[ a==b ]; echo $?
0
같은 이유로 에코.[[ a!=a ]]; echo $?
둘 다[ a!=a ]; echo $?
에코0
(예상)
<
따라서 조건식에서는 and 주위의 공백 만 생략할 수 있는 것처럼 보이지만 문자열 비교를 수행하는 것이 목적인 경우에는 생략할 수 없습니다. 그런데 왜 이렇게 설계되었을까요? 이것은 내가 놓친 것일 수도 있지만 bash 매뉴얼 어디에도 문서화되어 있지 않은 것 같습니다.>
=
==
!=
내 초기 문제는 조건식()에서 패턴의 일부로 >
이스케이프되지 않은 것을 사용하려고 하는 것이었습니다 . [[ ... ]]
나는 처음에 공백으로 둘러싸지 않는 한 >
문제 없이 사용할 수 있을 것이라고 생각했습니다. 왜냐하면 조건부 내에서 리디렉션하는 것은 의미가 없기 때문입니다(그리고 일부 테스트가 불가능한 것으로 판명된 후에는) 표현식이 작동할 것입니다. 또한.
그러나 이는 사실이 아닌 것으로 판명되었습니다. 물론 쉬운 해결책은 이스케이프 처리 >
하고 작성하는 \>
것이지만 왜 필요한지 이해가 되지 않습니다.
이것은 테스트에 사용한 bash 버전입니다.
GNU bash, version 5.2.2(1)-release (aarch64-unknown-linux-android)
그리고
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
내 실험은 env -i bash --norc --noprofile
.
답변1
&
이는 , ;
, (
, |
, <
, >
, 탭과 같은 문자가메타 문자쉘 구문에서. 그들은 자신의 토큰을 형성합니다(또는 더 많은 토큰으로 결합될 수 있습니다(예: ;;
, |&
, ||
...). 이는 문자²와 숫자가 유사한 [
, {
, !
, -
와 같은 문자와 다릅니다 .=
Korn 쉘의 구성 내부에서 [[...]]
쉘은 별도의 마이크로 언어를 이해하지만 외부와 거의 동일한 마크업 규칙을 따릅니다.
같은 이유로 외부에서는 [[...]]
다음을 수행할 수 있습니다.
(echo a>file|tr a b&)
그리고 그것을 쓸 필요가 없습니다 :
( echo a > file | tr a b & )
아니면 그런 것들도요 if((1))then<file&&(uname)fi
.
여기에서 다음을 수행할 수 있습니다.
[[(a>b||b<d)]]
(
, 및 >
는 쉘 메타문자 |
입니다 )
.
메타 문자를 문자 그대로 해석하려면 따옴표( '...'
, "..."
, \
, ... 포함)로 묶어야 합니다.$'...'
[[x]]
쉘은 하나의 [[x]]
토큰만 볼 수 있기 때문에 작동하지 않습니다. 그리고 구성을 [[
시작 하는 키워드 [[...]]
도 인식되지 않습니다. 마이크로 언어 와 [[ a==b ]]
달리 는 단일 토큰이므로 해석은 와 동일합니다 .[[ a == b ]]
[[...]]
a==b
[[ -n 'a==b' ]]
[
그 자체는 단지 일반적인 명령이므로 다른 명령과 동일한 방식으로 구문 분석됩니다.
[ a>b ]
[
a
및 인수 로 실행하면 ]
출력은 with 또는 와 마찬가지로 로 리디렉션 b
됩니다 .[ a ] > b
echo a>b ]
echo a ] > b
>b echo a ]
내부적으로 ((...))
(ksh와는 달리) C와 유사한 자체 마이크로 언어가 제공되지만 이번에는 토큰화 규칙이 다릅니다. 예를 들어 ((var=123+1))
or 를 쓸 수 있지만 or 는 필요 ((a==b))
하지 않습니다 .((var = 123 + 1))
((a == b))
1은 {
중괄호 확장에 참여하고 쉘 예약어이기도 하지만 토큰화 후 처리되지만 [
할당을 구문 분석할 때 토큰화에 참여합니다. 인수로 실행되지 a[1 + 1]=foo
않고 bash 또는 ksh(zsh 아님)에서 할당 단어로 구문 분석됩니다 . a[1
는 와 같은 예약어이지만 기록 확장에도 참여합니다. 단, 이는 셸의 대화형 호출에만 적용됩니다.+
1]=foo
!
{
-
² 일부 연산자에는 문자가 포함된다는 점에 유의하세요. [[...]]
예를 들어 -nt
, -eq
, -lt
...