bash 쉘과 다른 쉘 사이에서 test 또는 [또는 [[더 이식성이 좋은가?


44

내가 할 수있는 걸 봤어

$ [ -w /home/durrantm ] && echo "writable"
writable

또는

$ test -w /home/durrantm && echo "writable"
writable

또는

$ [[ -w /home/durrantm ]] && echo "writable"
writable

세 번째 구문을 사용하는 것이 좋습니다. 그것들은 모든면에서 그리고 모든 부정적인 경우와 동등한 경우에 동등합니까? Ubuntu의 bash와 OS X 또는 이전 / 이후 bash 버전 (예 : 4.0 이전 / 이후) 간의 이식성에 차이가 있습니까? 둘 다 같은 방식으로 식을 확장합니까?


2
대한 [ … ][[ … ]]test …, 더 완벽한 답변이 있습니다 이 대부분 중복 된 질문은 .
Gilles 'SO- 악한 중지

파일의 쓰기 가능성 테스트에 대한 특정 문제는 파일에 대한 쓰기 액세스를 비 침습적으로 테스트하는 방법을
G-Man, 'Reinstate

1
"휴대용 코드가없고 이식 된 코드 만 있습니다"라는 말이 있습니다. 이것에 관한 나의 충고 : 가장 읽기 쉬운 형식 (아마도 [[...]])을 사용하고 지원하려는 모든 플랫폼에서 시도하십시오. 스크립트를 가리는 데 많이 사용되지 않으므로 사용자 나 대상 사용자가 사용하지 않는 고대 플랫폼에서 실행됩니다. 코드를 읽기 어렵게 만들고 불필요한 버그를 발생 시키며 심지어 보안 문제 (openssl처럼)를 발생시킬 수도 있습니다.
stefan.schwetschke

답변:


31

[test명령의 동의어 이며 동시에 bash 내장 명령 과 별도 명령입니다. 그러나 [[A는 bash는 키워드 및 일부 버전에서 작동합니다. 따라서 이식성의 이유로 단일 []또는test

[ -w "/home/durrantm" ] && echo "writable"

2
[POSIX 내장 또는 Bash 내장입니까?
Sandburg

@Sandburg POSIX는 표준이므로 내장 기능을 사용할 수 없습니다. 인터프리터에 무언가를 내장해야하는지 여부를 정의하지 않고 단지해야 할 일을 정의합니다. 이 규칙은 형태 모두에 적용 test하고 [모두. 쉘이 자체적으로 평가를 수행 할 수 있으면 프로세스가 절약되고 다소 빨라지지만 결과는 동일해야합니다.
Bachsau

@Bachsau는 여전히 Sandburg의 질문에 대답하지 않는지 여부 [는 POSIX에 의해 정의되므로 최대한 휴대 가능합니다 (실수하지 않은 경우이 질문의 핵심 부분 인 것 같습니다)
JamesTheAwesomeDude

@Sandburg (그리고 다른 사람이 가로 질러 걸림돌로) : 네, 모두 모양 [test POSIX입니다 . "권장"이없는 것 같지만, 그들 사이에서 발견 할 수있는 유일한 차이점 ( test")은"옵션의 끝을 나타내는 구분 기호로 "-"인수를 인식하지 않아야 한다는 것입니다 . "(?- - " 인수의 끝으로 인식되어 [실제로 어쨌든 좋은 테스트 사례를 제시 할 수는 없습니다. [그러나 test난탈합니다 . 사용할 것입니다. IMO 는 우아해 보이지만 분명히 명령입니다)
JamesTheAwesomeDude

35

예, 차이점이 있습니다. 가장 휴대용은 test또는 [ ]입니다. 이것들은 모두 POSIX test사양의 일부입니다 .

if ... fi구조체는 또한 POSIX로 정의 완전 이식한다.

[[ ]]A는 ksh또한 일부 버전에 존재하는 기능 bash( 모든 현대적인 것들 에) zsh아마 다른 사람이 아니라에 존재하지 않는 sh거나 dash또는 다양한 다른 간단한 포탄입니다.

그래서, 스크립트가 휴대용하게 사용하는 [ ], test또는 if ... fi.


10
그냥 참고로, bash그리고 zsh지원 한 [[아주 긴 시간 동안 ( bash90 년대 후반, 그것을 추가 zsh늦어도 2000보다하고 있다면 나는 놀랄 것 이제까지 당신이없이 하나의 버전을 발생할 가능성이 있습니다 있도록 지원 부족) [[. 다른 POSIX 호환 쉘 (예 :) dash이 발생할 가능성이 훨씬 높습니다.
chepner

1
한 가지 흥미로운 특징은 [[매개 변수 확장을 인용 할 필요가 없다는 것 입니다. 공백 문자 [[-f $file]]$file포함 된 경우 이벤트가 작동합니다 .
helpermethod

2
@helpermethod, 내장 정규 표현식[[ $a =~ ^reg.*exp.*$' ]]
GnP

20

즉,주의 사항 [] && cmd과 동일하지 않습니다 if .. fi건설.

때로는 그 동작이 매우 비슷하기 때문에 [] && cmd대신 사용할 수 있습니다 if .. fi. 그러나 때때로. if 조건을 실행할 명령이 하나 이상 있거나 if .. else .. fi조심하고 논리 가 필요한 경우.

몇 가지 예 :

[ -z "$VAR" ] && ls file || echo wiiii

와 동일하지 않습니다

if [ -z $VAR ] ; then
  ls file
else
  echo wiii
fi

ls실패 echo하면으로 실행 되지 않기 때문에 실행됩니다 if.

또 다른 예:

[ -z "$VAR" ] && ls file && echo wiii

와 같지 않다

if [ -z "$VAR" ] ; then
   ls file
   echo $wiii
fi

이 구조는 동일하게 작동하지만

[ -z "$VAR" ] && { ls file ; echo wiii ; }

참고 ;에코 후이 중요하고이 있어야합니다.

위의 진술을 다시 시작하면

[] && cmd == 첫 번째 명령이 성공하면 다음 명령을 실행하십시오.

if .. fi == 조건 (테스트 명령 일 수도 있음)이면 명령을 실행합니다.

따라서 휴대 [성과 이식성 에만 [[사용하십시오 [.

ifPOSIX와 호환됩니다. 그래서 만약 당신이 사이에서 선택을 [하고 if귀하의 작업과 예상되는 동작을보고 선택합니다.


아마 밀도가 높을 지 모르지만 그 차이가 무엇인지 알지 못합니다 ...이 두 구조가 다른 결과를 줄 수있는 예를 들어 주시겠습니까?
evilsoup

1
@evilsoup이 업데이트되었습니다. 최고의 설명자가 아닐 수도 있지만 지금은 명확 해지기를 바랍니다.
돌진

1
아주 좋은 지적이야. 첫 번째 예제의 안전한 형식은 다음과 같습니다 [ -z "$VAR" ] && { ls file; true; } || echo wiiii. 조금 더 장황하지만 여전히 if...fi구조 보다 짧습니다 .
오후 2시

질문을 [vs [[vs 테스트 및 if ... fi vs &&에 관한 질문이 아닌) 한 질문으로 만들었습니다. 불행히도 그렇게하면이 대답은 오프 포인트로 보입니다. 처음에는 질문에 초점을 맞추지 않은 것에 대한 사과가이 문제를 일으켰다. 살고 배우십시오. :)
Michael Durrant

a) 이것은 주로 좋은 답변이지만 다른 질문에 대한 답변이기 때문에 하향 투표했습니다. b) 당신은 존재 [하고 if대체물로 있지만, 그렇지 않습니다. 실제로는 &&을 대체하는 것 if입니다. [많은처럼, 몇 가지 코드를 실행하고 상태를 반환 ls하고 grep있다. ifif 다음에 제공된 명령 (상태)의 반환 상태에 따라 분기 실행은 모든 명령 (상태) 일 수 있습니다. &&이전 문장이 간단한 것처럼 0을 반환 한 경우에만 다음 문장을 실행합니다 if..then..fi.
GnP

9

그것은 사실이다 &&를 대체하는 if,하지 test: if명령이 "성공"(영) 종료 상태를 반환 여부 쉘 스크립트 테스트에서 문; 귀하의 예에서 명령은 [입니다.

따라서 실제로 테스트를 실행하는 데 사용되는 명령과 해당 테스트 결과를 기반으로 코드를 실행하는 데 사용되는 구문의 두 가지가 있습니다.

테스트 명령 :

  • test표준화 된 명령 문자열 및 파일의 특성을 평가하는이; 귀하의 예에서, 당신은 명령을 실행하고 있습니다test -w /home/durrantm
  • [똑같이 표준화 된 명령의 별명이며 ], 괄호로 묶은 표현식처럼 보이기 위해 필수 마지막 인수가 있습니다 . 속지 말고 여전히 명령 일뿐입니다 (시스템에이라는 파일이 있음을 알 수 있습니다 /bin/[)
  • [[일부 쉘에 내장 된 테스트 명령의 확장 버전이지만 동일한 POSIX 표준의 일부는 아닙니다. 여기에 사용하지 않는 추가 옵션이 포함되어 있습니다.

조건식 :

  • &&(오퍼레이터 여기 표준화는 ) 두 명령을 평가하고 (참 나타내는) 0을 반환하여, 논리 AND 연산을 수행하는 경우 그들은 모두 복귀 0; 첫 번째 명령이 0을 반환하면 두 번째 명령 만 평가하므로 간단한 조건부로 사용할 수 있습니다.
  • if ... then ... fi(구조체 여기 표준화는 ) "진실"을 판정하는 방법과 동일한 방법을 사용하지만, 경고문의 화합물에서 허용 then오히려에 의해 제공되는 하나의 명령이 아닌, 절 &&, 단락 및 제공 elif하고 else쓰기에 어려운 조항, 만 사용 &&하고 ||. 명령문 의 조건 주위에는 괄호가 없습니다if .

따라서 다음은 예제와 동일하게 이식 가능하며 완전히 동등한 렌더링입니다.

  • test -w /home/durrantm && echo "writable"
  • [ -w /home/durrantm ] && echo "writable"
  • if test -w /home/durrantm; then echo "writable"; fi
  • if [ -w /home/durrantm ]; then echo "writable"; fi

다음은 비표준 적 특성으로 인해 동등하지만 휴대 성이 떨어집니다 [[.

  • [[ -w /home/durrantm ]] && echo "writable"
  • if [[ -w /home/durrantm ]]; then echo "writable"; fi

예, if .... fi 부분을 제거하여이 질문을 1 개의 질문으로 만듭니다.
Michael Durrant

7

이식성을 위해 test/를 사용하십시오 [. 그러나 이식성을 필요로하지 않는다면, 자신과 다른 사람들이 당신의 스크립트를 읽는 것을 위해 건강을 유지하기 위해 [[. :)

또한 참조 What is the difference between test, [ and [[ ?BashFAQ .


7

Bourne과 같은 세계 밖에서 이식성을 원한다면 :

test -w /home/durrantm && echo writable

가장 휴대용입니다. 그것은 Bourne의 껍질 cshrc가족 에서 작동합니다 .

test -w /home/durrantm && echo "writable"

겠습니까 출력 "writable"대신 writable의 껍질에 rc가족 ( rc, es, akanga, 어디 "특별하지 않습니다).

[ -w /home/durrantm ] && echo writable

명령 이없는 시스템 의 일부 csh또는 rc패밀리의 쉘에서는 작동 하지 않습니다 (일부는 별칭이 없는 것으로 알려져 있음 ).[$PATHtest[

if [ -w /home/durrantm ]; then echo writabe; fi

Bourne 가족의 껍질에서만 작동합니다.

[[ -w /home/durrantm ]] && echo writable

ksh(원산지) zshbash(본 가족의 3 명 ) 에서만 작동합니다 .

fish필요한 쉘에서는 아무것도 작동 하지 않습니다.

[ -w /home/durrantm ]; and echo writable

또는:

if [ -w /home/durrantm ]; echo writable; end

0

중 하나를 선택하는 나의 가장 중요한 이유 if foo; then bar; fi또는 foo && bar전체 명령의 종료 상태가 중요 여부입니다.

비교:

#!/bin/sh
set -e
foo && bar
do_baz

와:

#!/bin/sh
set -e
if foo; then bar; fi
do_baz

그들이 같은 것을 생각할 수도 있습니다. 그러나 foo실패하면 (또는 사용자의 관점에 따라 false 인 경우 ) 첫 번째 예제에서 스크립트가 종료 될 때 do_baz가 실행되지 않습니다 ... set -e명령이 false 상태를 리턴하면 쉘이 즉시 종료되도록 지시합니다. 다음과 같은 일을 할 때 매우 유용합니다.

cd /some/directory
rm -rf *

cd어떤 이유로 든 실패 할 경우 스크립트가 계속 실행되는 것을 원하지 않습니다 .


1
어떤 foo경우에도 스크립트가 중단되지 않습니다. set -e명령이 조건 (&& / ||의 왼쪽 또는 if / while / until / elsif ... 조건으로 평가 될 때)에 대한 특별한 경우입니다 . bar두 경우 모두 실패 하면 쉘이 종료됩니다.
Stéphane Chazelas

2
당신은 cd /some/directory && rm -rf -- *또는 cd /some/directory || exit; rm -rf -- *(여전히 숨겨진 파일을 제거하지 않습니다). 나는 개인적으로 set -e올바른 코드를 작성하려고 노력하지 않는 변명 으로 사용 하는 것을 좋아하지 않습니다 .
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.