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=$?
명령이 실패하지 않는 한 모든 경우에 echo
0으로 설정됩니다 .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의 실제 문제는 반환 코드를 안정적으로 얻을 수 없다는 것이었지만 다른 사람들이 이 문제를 해결한 것 같습니다.