명령이 빈 문자열을 출력하는지 테스트


237

명령이 빈 문자열을 출력하는지 어떻게 테스트 할 수 있습니까?


7
명령은 문자열을 반환하지 않지만 (성공의 경우 일반적으로 0, 실패시 1 또는 2의 작은 정수 종료 코드를 반환 함) 문자열에 입력하기 위해 일부 데이터를 출력 할 수 있습니다 .
Basile Starynkevitch

@BasileStarynkevitch 이것이 내가 필요로하는 것입니다. 명령이 종료 코드를 반환한다는 것을 알고 있지만 명령이 종료 코드는 항상 0이므로 출력을 제어해야합니다
barp

1
Bash 스크립팅 튜토리얼 tldp.org/LDP/abs/html을
Basile Starynkevitch

Joey Hess는이를위한 유틸리티 ifne를 가지고 있습니다. joeyh.name/code/moreutils
tripleee

답변:


309

이전에는 디렉토리에 파일이 있는지 확인하는 방법에 대한 질문이있었습니다. 다음 코드는이를 달성하지만 더 나은 솔루션 은 rsp의 답변 을 참조하십시오 .


빈 출력

명령은 값을 반환 하지 않고 출력합니다. 명령 대체 를 사용하여이 출력을 캡처 할 수 있습니다 . 예 $(ls -A). Bash에서 비어 있지 않은 문자열을 다음과 같이 테스트 할 수 있습니다.

if [[ $(ls -A) ]]; then
    echo "there are files"
else
    echo "no files found"
fi

심볼릭 현재 ( ) 및 부모 ( ) 디렉토리 항목 이 생략되어 있기 때문에 내가 -A아닌 사용 -a했습니다 ....

참고 : 주석에서 지적했듯이 명령 대체 는 후행 줄 바꿈을 캡처하지 않습니다 . 따라서 명령이 개행 출력 하면 대체는 아무것도 캡처하지 않고 테스트는 false를 리턴합니다. 아주 드물지만 위의 예에서는 단일 줄 바꿈이 유효한 파일 이름이므로 가능합니다! 이 답변에 대한 자세한 정보 .


종료 코드

명령이 성공적으로 완료되었는지 확인 $?하려면 마지막 명령의 종료 코드 (성공의 경우 0, 실패의 경우 0이 아님)를 포함하는 inspect를 검사 할 수 있습니다 . 예를 들면 다음과 같습니다.

files=$(ls -A)
if [[ $? != 0 ]]; then
    echo "Command failed."
elif [[ $files ]]; then
    echo "Files found."
else
    echo "No files found."
fi

자세한 내용은 여기를 참조하십시오 .


4
당신은 생략 할 수 있습니다 -n 그냥있을거야, 그래서if [[ $(ls -A) ]]; then
사용자

6
이 방법은 개행 만 출력하는 명령에 대해 false를 제공합니다.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

89

TL; DR

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then ...; fi

원본을 개선 할 것을 제안 하는 netj 에게 감사드립니다 .
if [[ $(ls -A | wc -c) -ne 0 ]]; then ...; fi


이것은 오래된 질문이지만 개선이 필요하거나 설명이 필요한 두 가지 이상이 있습니다.

첫 번째 문제

내가 본 첫 번째 문제는 여기에 제공된 대부분의 예제가 작동하지 않는다는 것 입니다. 빈 디렉토리에 비어 있지 않은 문자열을 출력 하는 ls -alls -Al명령을 사용합니다 . 이러한 예제 는 파일 이없는 경우에도 항상 파일이 있다고보고합니다 .

이러한 이유로 당신은 그냥 사용해야합니다 ls -A-왜 -l출력이 있는지 여부에 관계없이 원하는 것이 테스트 될 때 누군가가 "긴 목록 형식 사용"을 의미 하는 스위치를 사용하고 싶습니까?

따라서 대부분의 대답은 간단하지 않습니다.

두 번째 문제

두 번째 문제는 동안이다 일부 답변이 잘 작동 (사람들을 그 않는 사용 ls -al또는 ls -Al하지만 ls -A그들은 모두 같은 것을 할 대신) :

  1. 명령을 실행
  2. 전체 출력을 RAM에 버퍼링
  3. 출력을 거대한 단일 행 문자열로 변환
  4. 해당 문자열을 빈 문자열과 비교

내가 대신 제안하는 것은 다음과 같습니다.

  1. 명령을 실행
  2. 저장하지 않고 출력에서 ​​문자를 계산
    • 또는 더 나은-최대 1 자의 수를 세십시오 using head -c1
      ( 아래 의견 에이 아이디어를 게시 한 netj 덕분에 )
  3. 그 숫자를 0과 비교

예를 들어 다음 대신

if [[ $(ls -A) ]]

나는 사용할 것이다 :

if [[ $(ls -A | wc -c) -ne 0 ]]
# or:
if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]

대신에:

if [ -z "$(ls -lA)" ]

나는 사용할 것이다 :

if [ $(ls -lA | wc -c) -eq 0 ]
# or:
if [ $(ls -lA | head -c1 | wc -c) -eq 0 ]

등등.

작은 출력의 경우 문제가되지 않지만 큰 출력의 경우 차이가 클 수 있습니다.

$ time [ -z "$(seq 1 10000000)" ]

real    0m2.703s
user    0m2.485s
sys 0m0.347s

그것을 다음과 비교하십시오.

$ time [ $(seq 1 10000000 | wc -c) -eq 0 ]

real    0m0.128s
user    0m0.081s
sys 0m0.105s

그리고 더 나은 :

$ time [ $(seq 1 10000000 | head -c1 | wc -c) -eq 0 ]

real    0m0.004s
user    0m0.000s
sys 0m0.007s

전체 예

Will Vousden의 답변에서 업데이트 된 예 :

if [[ $(ls -A | wc -c) -ne 0 ]]; then
    echo "there are files"
else
    echo "no files found"
fi

netj의 제안 후 다시 업데이트되었습니다 .

if [[ $(ls -A | head -c1 | wc -c) -ne 0 ]]; then
    echo "there are files"
else
    echo "no files found"
fi

jakeonfire의 추가 업데이트 :

grep일치하지 않으면 실패와 함께 종료됩니다. 구문을 약간 단순화하기 위해이를 활용할 수 있습니다.

if ls -A | head -c1 | grep -E '.'; then
    echo "there are files"
fi

if ! ls -A | head -c1 | grep -E '.'; then
    echo "no files found"
fi

공백 무시

테스트중인 명령이 빈 문자열로 처리 할 공백을 출력 할 수있는 경우 대신 다음을 수행하십시오.

| wc -c

당신은 사용할 수 있습니다 :

| tr -d ' \n\r\t ' | wc -c

또는 함께 head -c1:

| tr -d ' \n\r\t ' | head -c1 | wc -c

또는 그런 것.

요약

  1. 먼저 작동 하는 명령을 사용하십시오 .

  2. 둘째, 불필요한 RAM 저장 및 잠재적으로 큰 데이터 처리를 피하십시오.

답은 출력이 항상 작다는 것을 명시하지 않았으므로 큰 출력의 가능성도 고려해야합니다.


3
[[ $(... | head -c | wc -c) -gt 0 ]]또는 명령의 전체 출력을 사용해야 [[ -n $(... | head -c1) ]]하므로 더 좋습니다 wc -c.
netj

@netj 이것은 매우 좋은 생각입니다. 내 업데이트 된 답변을 참조하십시오-귀하의 제안을 추가했습니다. 고마워요!
rsp

출력을 유지하는 방법에 대한 아이디어가 있습니까?
fahrradflucht

나는 일반적인 경우 머리가없는 원본이 더 좋다고 생각합니다. 출력을 쓰기 시작하자마자 명령을 종료하는 것이 항상 좋은 생각은 아닙니다!
stk

@stk 대부분의 프로그램은 kill 신호를받은 후 안전하게 종료됩니다.
모호한

40
if [ -z "$(ls -lA)" ]; then
  echo "no files found"
else
  echo "There are files"
fi

명령을 실행하고 반환 된 출력 (문자열)의 길이가 0인지 확인합니다. 다른 플래그에 대해서는 'test'매뉴얼 페이지 를 확인하십시오 .

검사중인 인수 주위에 ""를 사용하십시오. 그렇지 않으면 빈 검사 결과에 두 번째 인수 (확인)가 없으므로 구문 오류가 발생합니다!

참고 : 것을 ls -la항상 반환 .하고 ..그래서하지 않습니다 작업을 사용하여이 참조 LS에게 매뉴얼 페이지를 . 또한 이것이 편리하고 쉬운 것처럼 보이지만 쉽게 깨질 것이라고 생각합니다. 결과에 따라 0 또는 1을 반환하는 작은 스크립트 / 응용 프로그램을 작성하는 것이 훨씬 더 안정적입니다!


당신이 사용하는 것을 선호 수도 $(, 대신 역 인용 부호로 인해 $(더 나은 둥지
실레 Starynkevitch

여기에 중첩 할 필요는 없지만 항상 사용하는 것이 좋습니다.
Veger

23

우아하고 bash 버전 독립적 인 솔루션을 원하거나 (현대 다른 쉘에서 작동해야 함) 빠른 작업을 위해 하나의 라이너를 사용하는 것을 좋아하는 사람들을 위해. 우리는 간다!

ls | grep . && echo 'files found' || echo 'files not found'

(주 코멘트 중 하나를 언급 한 바와 같이, ls -al사실, 단지 -l-a모든 반환 뭔가, 그래서 내 대답에 나는 간단한을 사용합니다ls


5
당신이 사용하는 경우 grep -q ^대신, 줄 바꿈 문자도 일치하며, GREP은 표준 출력에 아무것도 인쇄되지 않습니다. 또한 입력 스트림이 끝나기를 기다리지 않고 입력을받는 즉시 종료됩니다.
mortehu

ls -A도트 파일 (또는 디렉토리)을 포함하려면 먼저 시작해야합니다.
wrlee

13

배쉬 참조 매뉴얼

6.4 배쉬 조건식

-z string
     True if the length of string is zero.

-n string
string
     True if the length of string is non-zero.

속기 버전을 사용할 수 있습니다.

if [[ $(ls -A) ]]; then
  echo "there are files"
else
  echo "no files found"
fi

1
괄호 [-...]에 -z 또는 -n이 없습니다.
71GA

4
@ 71GA : 아마도 간과하기 쉽지만주의 깊게 살펴보면 string의 동의어 일뿐 입니다 -n string.
사용자

10

Jon Lin이 언급했듯이 ls -al항상 (for ...)을 출력 합니다. ls -Al이 두 디렉토리를 피 하려고 합니다.

예를 들어 명령 출력을 쉘 변수에 넣을 수 있습니다.

v=$(ls -Al)

더 오래된, 중첩 할 수없는 표기법은

v=`ls -Al`

하지만 중첩 가능한 표기법을 선호합니다 $(...)

해당 변수가 비어 있지 않은지 테스트 할 수 있습니다

if [ -n "$v" ]; then
    echo there are files
else
    echo no files
fi

그리고 당신은 둘 다를 결합 할 수 있습니다 if [ -n "$(ls -Al)" ]; then


5

나는 당신이 ls -al명령 의 출력을 원한다고 추측한다 . 그래서 bash에서는 다음과 같은 것을 가질 것이다.

LS=`ls -la`

if [ -n "$LS" ]; then
  echo "there are files"
else
  echo "no files found"
fi

작동하지 않습니다 : 명령 ls이 실행되지 않습니다. 변수확장이LS 비어 있지 않은지 확인하십시오 .
gniourf_gniourf

1
@gniourf_gniourf-어떻게 생각하세요? 백틱 (backtick) 주문은 $ ()만큼이나 유연하지는 않지만 인정합니다.
tink

-a스위치 (이 파일입니다 여부 즉,이 내용을 반환합니다) 항상 암시가 있기 때문에 어떤 내용을 반환하지 않습니다 ...디렉토리 존재.
wrlee

3

보다 극단적 인 경우에 대한 해결책은 다음과 같습니다.

if [ `command | head -c1 | wc -c` -gt 0 ]; then ...; fi

이 작동합니다

  • 모든 Bourne 포탄;
  • 명령 출력이 모두 0이면;
  • 출력 크기에 관계없이 효율적으로;

하나,

  • 명령이 출력되면 명령 또는 해당 하위 프로세스가 종료됩니다.

1

지금까지 제공된 모든 대답 은 비어 있지 않은 문자열 종료 하고 출력하는 명령을 처리 합니다.

대부분의 의미는 다음과 같습니다.

  • 개행 만 출력하는 명령을 제대로 처리하지 못합니다.
  • 명령이 널 바이트를 출력하면 (명령 대체를 사용할 때) Bash≥4.4부터 시작하면 대부분 스팸 표준 오류가 발생합니다.
  • 대부분은 전체 출력 스트림을 처리하므로 명령이 종료 될 때까지 기다렸다가 응답합니다. 일부 명령은 종료되지 않습니다 (예 :) yes.

이러한 모든 문제를 해결하고 다음 질문에 효율적으로 답변하려면

명령이 빈 문자열을 출력하는지 어떻게 테스트 할 수 있습니까?

당신이 사용할 수있는:

if read -n1 -d '' < <(command_here); then
    echo "Command outputs something"
else
    echo "Command doesn't output anything"
fi

read-t옵션을 사용하여 명령이 주어진 시간 내에 비어 있지 않은 문자열을 출력하는지 테스트하기 위해 시간 초과를 추가 할 수도 있습니다 . 예를 들어, 2.5 초 시간 초과 :

if read -t2.5 -n1 -d '' < <(command_here); then
    echo "Command outputs something"
else
    echo "Command doesn't output anything"
fi

말. 명령이 비어 있지 않은 문자열을 출력하는지 여부를 결정해야한다면 XY 문제 일 가능성이 큽니다.


나는이 대답이 다소 감사하다고 생각한다. 여기 3 개 입력 시나리오마다 100 번 반복하여 용액의 일부 성능 테스트 하였다 ( seq 1 10000000, seq 1 20printf""). 이 읽기 접근 방식이 이기지 못한 유일한 매치업 -z "$(command)"은 빈 입력에 대한 접근 방식입니다. 그렇더라도 약 10-15 % 만 손실됩니다. 그들은 심지어 주위를 깰 것 같다 seq 1 10. 그럼에도 불구 하고 입력 크기가 커질 -z "$(command)"수록 접근 방식이 너무 느려져 가변 크기 입력에 사용하지 않는 것이 좋습니다.
abathur

0

다음은 일부 명령의 std-out 및 std-err에 임시 파일을 쓴 다음 해당 파일이 비어 있는지 확인하는 대체 방법입니다. 이 방법의 장점은 두 출력을 모두 캡처하고 하위 셸 또는 파이프를 사용하지 않는다는 것입니다. 후자의 측면은 bash 종료 처리 트래핑을 방해 할 수 있으므로 중요합니다 (예 : 여기 )

tmpfile=$(mktemp)
some-command  &> "$tmpfile"
if [[ $? != 0 ]]; then
    echo "Command failed"
elif [[ -s "$tmpfile" ]]; then
    echo "Command generated output"
else
    echo "Command has no output"
fi
rm -f "$tmpfile"

0

비어 있지 않은 경우 출력을 저장하여 다른 명령으로 전달하려는 경우가 있습니다. 그렇다면 다음과 같은 것을 사용할 수 있습니다

list=`grep -l "MY_DESIRED_STRING" *.log `
if [ $? -eq 0 ]
then
    /bin/rm $list
fi

이렇게 rm하면 목록이 비어 있으면 명령이 중단되지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.