![서브셸 변수 제한을 호출하지 않고 "&&" 또는 "||" 뒤에 명령을 그룹화하는 방법은 무엇입니까? [복사]](https://linux55.com/image/119480/%EC%84%9C%EB%B8%8C%EC%85%B8%20%EB%B3%80%EC%88%98%20%EC%A0%9C%ED%95%9C%EC%9D%84%20%ED%98%B8%EC%B6%9C%ED%95%98%EC%A7%80%20%EC%95%8A%EA%B3%A0%20%22%26amp%3B%26amp%3B%22%20%EB%98%90%EB%8A%94%20%22%7C%7C%22%20%EB%92%A4%EC%97%90%20%EB%AA%85%EB%A0%B9%EC%9D%84%20%EA%B7%B8%EB%A3%B9%ED%99%94%ED%95%98%EB%8A%94%20%EB%B0%A9%EB%B2%95%EC%9D%80%20%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C%3F%20%5B%EB%B3%B5%EC%82%AC%5D.png)
스크립트는 단순히 파일을 foo
에 복사하려고 시도하고 bar/
, 실패할 경우 2번 더 재시도합니다.
편집하다:두 번째 예제는 작동하고 첫 번째 예제는 작동하지 않는 이유는 (...)
or 분기 이후에 명령 집합을 실행하는 것이 하위 쉘로 간주되어 외부 변수에 영향을 주지 않기 때문입니다.&&
||
그래서 수정된 질문은 다음과 같습니다.첫 번째 예와 같이 일부 명령을 그룹화하되 서브셸을 사용하지 않고 수행하려면 어떻게 해야 합니까?
편집 2:대답 ( ... )
은 { ...; }
!
#!/usr/bin/env bash
#
# Be safe
set -euo pipefail
# Init variables
__file="foo"
output_dir="bar"
logfile="test.log"
errorlevel=8
count=0
# Try three times to copy a file
until (( errorlevel == 0 || count == 3 )); do
cp -Lv --no-preserve=mode \
"$__file" \
"$output_dir/" \
| tee -a "$logfile" \
&& (errorlevel=$?; echo "zero return, $errorlevel") \
|| (errorlevel=$?; echo "non-zero return, $errorlevel")
echo "errorlevel $errorlevel"
(( ++count ))
echo "count $count"
done
unset errorlevel
unset count
질문:
복사가 실패하거나 성공하면 ||
또는 분기는 포함된 분기에서 알 수 있듯이 &&
변수를 올바르게 캡처하고 각각 으로 설정 합니다 errorlevel
.1
0
echo $errorlevel
그러나 다음 명령(또한 echo)은 초기 변수 값을 반환합니다 8
. 왜 이런 일이 발생하는지 이해할 수 없습니다.
몇 가지 참고사항:
- 나는 이 스크립트를 가능한 한 안전하게 만들어야 하기 때문에 명시적으로
&&
and를 사용합니다 (실제로는 1500줄 스크립트의 작은 루틴입니다). 0이 아닌 반환 캡처를 사용하지 않으면 스크립트가 종료됩니다. 또는 and를 사용하지 않고도 복사 루틴을 수행한 다음 (오류 수준을 한 번 포착하여) 다시 사용할 수 있지만 스크립트의 나머지 스타일과 일치하지 않기 때문에 그렇게 하지 않는 것이 좋습니다. .||
set -e
||
set +e
&&
||
set -e
- 나는 항상 내 종료를 덮어쓰지 않도록
set -o pipefail
파이프라인에서 0이 아닌 오류 수준을 전달하는 데 사용합니다 .tee -a "$logfile"
errorlevel
- 전자는 0 오류 수준을 반환하고 후자는 0이 아닌 오류 수준을 반환하기 때문에
++count
대신 사용합니다 (그리고 주석 #1의 설명 으로 인해 추악한 작업을 수행해야 합니다).count++
(( count++ )) || true
set -e
errorlevel
이제 변수를 명시적으로 설정하여 이 1
문제를 해결했습니다. 0이 아닌 값이 무엇인지 0
는 실제로 신경 쓰지 않기 때문입니다 errorlevel
. 하지만 여전히 위의 내용이 예상대로 작동하지 않는 이유를 알고 싶습니다.
해결책은 다음과 같습니다.
#!/usr/bin/env bash
#
set -euo pipefail
__file="foo"
output_dir="bar"
logfile="test.log"
errorlevel=1
count=0
until (( errorlevel == 0 || count == 5 )); do
cp -Lv --no-preserve=mode \
"$__file" \
"$output_dir/" \
| tee -a "$logfile" \
&& errorlevel=0 \
|| errorlevel=1
(( ++count ))
sleep 1
done
unset errorlevel
unset count
어떤 통찰력이라도 대단히 감사하겠습니다!
답변1
나는 if
블록을 사용하는 것을 선호합니다:
errorlevel=0
if cp -Lv --no-preserve=mode \
"$__file" \
"$output_dir/" \
| tee -a "$logfile"
then
echo "zero return, $errorlevel"
else
errorlevel=$?
echo "non-zero return, $errorlevel"
fi
if
0이 아닌 종료 상태가 -e
잘못된 종료 작업을 트리거하는 것을 방지합니다 .
(물론 원래 문제는 ( )
하위 쉘을 생성하여 변수 할당이 상위 쉘에 영향을 미치지 않도록 하는 것이었습니다.)