빈 문자열에 -d를 사용하여 폴더가 있는지 확인하는 이유는 무엇입니까?


8

나는 스크립트를 쓰고 있었고 다음과 같이 썼다.

ARTIFACTS="/SOME/PATH"
[ -d $ARTIFCATS ] && rm -rf $ARTIFACTS/*

일어난 일은 어리 석음으로 인해 첫 번째 줄을 실행하지 않고 두 번째 줄을 실행했습니다. [-d ""]는 true를 반환하고 표현식은

rm -rf /*

운 좋게도 그것은 단지 테스트 머신이었고 나는 sudo가 아니었지만 데이터를 잃어 버렸지 만

내 질문은 왜 [-d ""]가 true를 반환하는 것입니까? 문서에는 경로가 존재하고 폴더인지 확인하는 내용이 명확하게 나와 있습니다.

나는을 사용하여 문제를 해결했다.

[ -e $ARTIFACTS ]
작동하는 것 같습니다

건배


5
아니면 두 줄을 모두 실행했을 수도 있습니다. 위의 코드 예제에서는 ARTIFCATS를 설정하지 않았습니다.
Buhb

2
나는 그냥 rm -rf $ARTIFACTS없이 그것을 쓸 것 /*입니다. 이것은 $ARTIFACTS디렉토리를 삭제합니다. 디렉토리에 무언가를 넣기 전에 디렉토리가 존재하는지 확인하려면 mkdir -p $ARTIFACTS어쨌든 실행하기 때문입니다. 또한 내부 파일을 숨겨 삭제합니다 $ARTIFACTS내가 쓸 때문에, 미세 또한 인 rm -rf $ARTIFACTS/*경우 $ARTIFACTS포함 된 것도 내가 저장하고 싶어합니다.
Christoffer Hammarström

@ ChristofferHammarström 매우 사실
Moataz Elmasry

답변:


9

1.이 두 테스트는 true를 반환 합니다 .

# [ -d ] && echo true || echo false
true
# [ -d $SOME_UNSET_VAR ] && echo true || echo false
true

POSIX에 따라 (@Tim에서 설명).

2. 그러나 이것은 거짓을 반환합니다 ( 질문에 명시된 바와 같이 사실아닙니다 )

# [ -d "" ] && echo true || echo false
false

왜냐하면 test두 개의 인수로 호출 되기 때문 입니다 (두 번째는 빈 문자열 임).

3. 이것이 대부분의 현재 쉘이 제공하는 ( ) [[ … ]]대신에 사용하는 것이 좋습니다 . 이 구문은 충분한 인수를 제공하는지 확인합니다 (그렇지 않으면 오류가 발생하고 중단됨)test[ … ]

# [[ -d ]] && echo true || echo false
bash: unexpected argument `]]' to conditional unary operator
bash: syntax error near `]]'

또는 단순히 예상대로 행동합니다.

# [[ -d $SOME_UNSET_VAR ]] && echo true || echo false
false

4. @Gilles가 지적한 것처럼, 더 중요한 것은 큰 따옴표로 치환하는 것입니다. 따라서 (경우 2 와 동일)로 -d "$SOME_UNSET_VAR"확장하여 false를-d "" 반환합니다 . 따라서 이것은 Bourne 쉘과도 호환됩니다 .testsh

# [ -d "$SOME_UNSET_VAR" ] && echo true || echo false
false

bash 3.00.16 (1) 및 4.1.5 (1)로 테스트


1
Bash, ksh 및 zsh는 제공 [[ … ]]하지만 일반은 아닙니다 sh. 진짜로 중요한 연습하는 명령 대체 주위에 따옴표를 넣어 : [ -d "$ARTIFACTS" ].
Gilles 'SO- 악마 중지

6

이 질문은 이미 StackOverflow 에서 답변 되었습니다 . POSIX 표준에 따르면, test비어 있지 않은 하나의 인수 (다른 인수는 없음)로 호출 된 경우 항상 성공을 반환해야한다고합니다.

이것은 또한 test -e(그리고 실제로 내 시스템에 있음) 반드시 그러해야하므로주의하십시오.

대신 다음을 사용하십시오.

[ -d "$ARTIFACTS" ]

test 그런 다음 변수가 비어 있어도 두 개의 인수로 호출되어이 경우 false를 반환합니다.


"정확히 하나의 비어 있지 않은 논쟁." -이것은 오해의 소지가있는 요약입니다. 언급 한 페이지가 정확히 하나의 인수로 호출되고 해당 인수가 비어 있지 않은 링크입니다. 비어 있지 않은 인수 뒤에 빈 인수가없는 경우에 대해서는 올바른 해결책은 변수 이름을 따옴표로 묶어야합니다.
Random832

감사합니다! 제안 된 변경 사항을 모두 구현했습니다.
Tim

[ ! -z $ARTIFACTS ] && [ -d $ARTIFACTS ]더 낫지는 않습니다. $ARTIFACTS비어 있을 때만 특정 경우를 충족 시키지만 $ARTIFACTS공백 또는가 포함될 수는 없습니다 \[?*. [ -d "$ARTIFACTS" ]그것을하는 올바른 방법입니다 (또는 [[ -d $ARTIFACTS ]]을 가진 쉘에서 [[ … ]]).
Gilles 'SO- 악마 그만해

@Gilles 당신이 옳아 요, 그것을 제거했습니다. 감사합니다!
Tim

4

작동하는 것 같은 [-e $ ARTIFACTS]를 사용하여 문제를 해결했습니다.

당신은 틀 렸습니다 . $ARTIFACTS이제 무언가로 설정되어 있기 때문에 작동 합니다.

변수가 설정되지 않은 경우

[ -d $SOMEVAR ]

또는

[ -e $SOMEVAR ]

모두 에 평가 true가 말하는 의미하기 때문에

[ -d ]

[ -e ]

각기. 말 [ foobar ]은 항상 참으로 평가됩니다.

속담

set -u

이러한 상황에서 유용합니다. help set당신에게 말할 것입니다 :

  -u  Treat unset variables as an error when substituting.

[-e ""] && echo "PRINT SOMETHING"이 인쇄되지 않습니다. 어떻게 잘못 될 수 있습니까?
Moataz Elmasry

2
빈 아티팩트가있는 ahh crap [-e $ ARTIFACTS]은 [-e ""]가 아닌 [-e]를

4

변수 ARTIFACTS를 설정했고 ARTIFCATS를 확인하고 있음을 참조하십시오. 아마 엉망?

어쨌든 -d와 -e는 설정되지 않은 변수에 대해 동일한 결과를 생성합니다.

따라서 큰 따옴표를 사용 하면 도움이 될 것입니다.

ARTIFACTS="/SOME/PATH"
[ -d "$ARTIFACTS" ] && rm -rf -- "$ARTIFACTS/"*

참고 : "/ SOME / PATH"에 공간이있는 폴더가있는 경우 언급 한 스크립트가 "이진 연산자 예상"오류와 함께 중단됩니다.

예:

ARTIFACTS="/home backup/"

1) [ -d $ARTIFACTS ] && rm -rf $ARTIFACTS/*
bash: [: /home: binary operator expected

2) [ -d "$ARTIFACTS" ] && rm -rf "$ARTIFACTS"/*

잘 할 것입니다. rm호출 에 따옴표를 넣는 것을 잊지 마십시오 ( 기존의 존재하지 않는 것에 대해 rm -rf $ARTIFACTS유쾌하게 제거 /home하고 불평합니다 backup/*).

또한 -L확인을 포함 하면 디렉토리가 디렉토리에 대한 심볼릭 링크가 아닌 디렉토리인지 확인합니다.

그래서 기본적으로,

[ -d "$ARTIFACTS" && ! -L "$ARTIFACTS" ] && rm -rf -- "$ARTIFACTS"/*
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.