-eq: 단항 연산자가 필요합니다. [해제]

-eq: 단항 연산자가 필요합니다. [해제]
x=$?
if [ ${x} -eq '0' ]; then
echo "something missing"
exit 1
else
echo "all present"
fi

위의 명령을 실행할 -eq: unary operator expected때 왜 이런 일이 발생합니까 ?

내가 하고 있는 일의 보다 완전한 버전:

`cat ${2}`에 있는 파일 #$2의 경우 file.txt입니다.
하다
    만약에[ ! -f "${1}/${file}"] # $1은 경로입니다.
    그 다음에
        echo "$file이 없습니다"
        노톡=$?
    필리핀 제도
완벽한
if [ ${notok} -eq 0 ];
그 다음에
    echo "확인이 필요합니다"
    1번출구
기타
    echo "모든 파일이 존재합니다"
필리핀 제도

답변1

변수가 x정의되지 않은 것 같습니다.

시도 해봐

if [ ${x-1} -eq 0 ]

정의되거나 정의되지 않은 경우 값은 ${x-1}로 평가됩니다 $x.1

아니면 이전에 명령이 있었다고 가정하고 x=$?사용하는 것이 더 좋습니다.

if cmd arg1 ... argn
then
    # true
else
    # false
fi

답변2

좋아, 이제 질문을 편집했으므로 정확히 무슨 일이 일어나고 있는지 알 것 같습니다.

일부 파일이 포함된 디렉터리( )와 일부 파일 이름이 포함된 ~/dir텍스트 파일( )이 있다고 가정해 보겠습니다.~/file.txt

$ ls ~/dir
1.txt  2.txt  3.txt  4.txt  5.txt
$ cat ~/file.txt
1.txt
2.txt
3.txt
4.txt
5.txt

내가 아는 한, 귀하의 스크립트는 내용을 읽고 해당 파일 ~/file.txt( 등) 1.txt이 .2.txt~/dir

그러나 스크립트가 실행되면:

$ script.sh ~/dir ~/file.txt
/home/user/bin/script.sh: line 11: [: -eq: unary operator expected
All files present

그래서 무슨 일이 일어났나요? 다음 코드 발췌 부분을 살펴보세요.

if [ ! -f "${1}/${file}" ]; # $1 is a path 
then 
    echo "$file is missing" 
    notok=$? 
fi

~/dir여기서 가장 큰 결점은 과 의 내용이 ~/file.txt일치 하면 echo "$file is missing"; notok=$?절대 실행되지 않는다는 것입니다. 그런 다음 notok변수에 값이 없으면 확장이 null이기 [ ${notok} -eq 0 ]때문에 실패합니다 (많은 사람들이 의심하는 것처럼).${notok}

이 결함은 유일한 결함은 아니지만 오류가 발생하는 이유입니다 [: -eq: unary operator expected.

어떻게 해결하나요?

스크립트를 다시 작성하고 싶지 않다면 notok변수를 초기화하세요.어떤 숫자와도 다르게0메인 코드 앞에. 예를 들어:

notok='1'

for file in `cat ${2}` #$2 is file.txt 
do 
    if [ ! -f "${1}/${file}" ]; # $1 is a path 
    then 
        echo "$file is missing" 
        notok=$? 
    fi 
done 
if [ ${notok} -eq 0 ]; 
then 
    echo "need to check" 
    exit 1 
else 
    echo "All files present" 
fi

효과가있다:

# When the content of ~/dir and ~/file.txt matches
$ ls ~/dir
1.txt  2.txt  3.txt  4.txt  5.txt
$ cat ~/file.txt
1.txt
2.txt
3.txt
4.txt
5.txt
$ script.sh ~/dir ~/file.txt
All files present

# When the content of ~/dir and ~/file.txt does not match
$ ls ~/dir
1.txt  2.txt  3.txt  4.txt  5.txt
$ cat ~/file.txt
foo
1.txt
2.txt
3.txt
4.txt
5.txt
$ script.sh ~/dir ~/file.txt
foo is missing
need to check

하지만 스크립트를 다시 작성하려면 다음과 같이 하세요.

# Initialize variables
# It's possible to parse arguments like `-d DIR -f FILE` but let's keep simple
dir="${1}"
txt="${2}"
missing='0'

# Don't read lines with for!
while IFS='' read -r 'file'; do
  if [ ! -f "${dir}/${file}" ]; then
    echo "Missing file: ${file}"
    # Use a simple counter instead of catch the exit code of `echo`
    missing=$(( missing + 1 ))
  fi
done < "${txt}"

if [ "${missing}" -gt '0' ]; then
  echo "Total: ${missing}"
  exit '1'
else
  echo 'All files are present'
fi

답변3

내 생각에 당신이 정말로 원하는 것은 다음과 같습니다 rsync.

rsync --list-only --files-from="$2" "$1" "$1/.."

마지막 매개변수는 더미 매개변수이지만 필수입니다. $1자신과 동일한 디렉토리가 아닌 한 모든 디렉토리일 수 있습니다.

또는 원하는 것이 종료 상태이고 덜 장황한 경우:

rsync --dry-run --files-from="$2" "$1" "$1/.."

( 2>/dev/null원하는 경우 선택적으로 추가할 수 있습니다.진짜상태를 종료하면됩니다. )


이제 귀하가 게시한 손상된 스크립트를 되돌아보면 다음과 같습니다.

for file in `cat ${2}` #$2 is file.txt 

백틱은 더 이상 사용되지 않습니다.cmd백틱(예: *sh )은 셸에서 더 이상 사용되지 않습니까?

전달하는 파일 이름에는 $2이름에 공백이나 특수 문자가 없다고 가정합니다.공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?

당신은 또한 가정나열된 모든 파일이름에는 $2특수 문자나 공백이 없습니다 .

그리고 목록이 쉘 인수 목록의 최대 길이를 초과하지 않을 만큼 충분히 짧다고 가정합니다. 목록에 와일드카드(예 /*/*/*/*/../../../../*/*/*/*: )가 포함되어 있으면 수많은 문제가 발생하게 됩니다.

do 
    if [ ! -f "${1}/${file}" ]; # $1 is a path 

너 정말오직일반 파일을 허용하시겠습니까? 어떤 종류의 특수 파일도 아니고 디렉토리도 아니죠? 그렇다면 rsync이전에 제공한 명령을 수정해야 할 수도 있습니다.

또한 스타일 포인트는 다음과 같습니다.! 앞으로당신을 잘못된 길로 이끌 가능성 이 [적습니다 . if ! [ -f "$1/$file" ]그러나 이 특정한 경우에는 아무런 문제가 없습니다. ( [ ! ... ]이것을 누락된 큰따옴표와 결합 하면매우잘못된 길로 인도되는 것이 가능합니다. )

    then 
        echo "$file is missing" 
        notok=$? 

명령이 실패하지 않는 한 모든 경우에 echo0으로 설정됩니다 .notok

이미 종료 상태를 확인했다는 사실을 깨닫는 것은 더욱 어리석은 일입니다. 이 작업을 다시 수행할 필요는 없습니다. 여기에 작성 하고 스크립트 상단에 notok=1추가 하면 더 간단하고 더 나은 형식을 얻을 수 있습니다.notok=0

    fi 
done 
if [ ${notok} -eq 0 ]; 

큰따옴표 문자가 누락되었습니다. 다시, 참조공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?(그리고 부제목 "강력한 파일 이름 처리 및 쉘 스크립트에서 전달되는 기타 문자열에 대한 입문 가이드"를 참고하세요.)

then 
    echo "need to check" 

이 소식은 전혀 말이 되지 않습니다. 확인해야 할 사항이 있나요? 누가 무엇을 확인해야 합니까? 아?

    exit 1 
else 
    echo "All files present" 
fi

나머지는 괜찮습니다. 예.


대체 스크립트

if rsync --dry-run --files-from="$2" "$1" "$1/.." 2>/dev/null; then
  echo "All files present"
else
  echo "need to check"
  exit 1
fi

목록에 있는 디렉터리에 대한 대체 스크립트는 허용되지 않습니다(오류가 발생합니다).

if ! rsync --dry-run --files-from="$2" "$1" "$1/.." --no-dirs 2>&1 | grep -q .; then
  echo "All files present"
else
  echo "need to check"
  exit 1
fi

답변4

나는 긴 대본을 좋아하지만,

if [ X”$x” = X”0” ] ; then doThis ; else doThat ;fi

완전히 정확하지는 않더라도 적절합니다. 시작하지 마세요. FreeBSD 라이브러리의 일부 스크립트에서 이것을 본 적이 있습니다. OP의 실제 문제는 반환 코드를 안정적으로 얻을 수 없다는 것이었지만 다른 사람들이 이 문제를 해결한 것 같습니다.

관련 정보