나는 컴퓨터에서의 일상적인 작업을 용이하게 하기 위해 쉘 스크립팅을 배우고 있습니다.
Python에는 예외 처리를 위한 EAFP 스타일("허가보다 용서를 구하는 것이 더 쉽습니다")이 있습니다.
>>> while True:
... try:
... x = int(input("Please enter a number: "))
... break
... except ValueError:
... print("Oops! That was no valid number. Try again...")
이 스타일을 쉘 스크립트에서 사용할 수 있습니까?
답변1
EAFP를 어떻게 해석하느냐에 따라 다릅니다. 좁은 의미에서는 Python이 설계되었지만 일부 언어에서는 불가능하고 대부분의 다른 언어에서는 흔하지 않으며 강력히 권장되지 않는 예외 처리의 사용을 의미합니다. 그러나 더 넓은 의미에서 EAFP는 거의 모든 프로그래밍 언어, 특히 쉘 스크립트에서 일반적입니다.
나는 가정한다POSIX 쉘 스크립트, 조금주의를 기울이십시오불다. Python 코드 예제는 Python 3입니다.
허락 대신 용서를 구하는 방법은 여러 가지가 있습니다…
Python은 이분법과 가장 밀접하게 연관된 프로그래밍 언어입니다.행동하기 전에 생각하라(LBYL)그리고허락보다 용서를 구하는 것이 더 쉽다(EAFP). Python에서 EAFP는 일반적으로 LBYL 방식인 작업을 시도하기 전에 작업이 성공할지 여부를 확인하는 대신 예외가 발생하도록 허용하고 이를 포착하는 것을 의미합니다.
그러나 이것이 유일한 두 가지 가능성은 아닙니다. 실패할 경우 예외를 발생시키지 않는 작업을 시도할 수 있지만 시도한 후에 실패했는지 확인하고 결과에 따라 다른 조치를 취하는 것이 가능합니다. 예외 처리를 사용하지 않으므로 Python 관점에서 EAFP라고 부르는 것이 이상하게 느껴지지만 실제로는 LBYL보다 EAFP와 더 많은 공통점이 있습니다. 이 "EAFP"는 쉘 스크립팅에서 매우 일반적입니다.
Python 예제로 시작하는 것이 도움이 된다고 생각합니다. 이러한 용어는 Python 문화와 밀접하게 관련되어 있을 뿐만 아니라 EAFP, LBYL 및 "EAFP" 예외를 Python에서 깔끔하고 간단한 방식으로 모두 시연할 수 있기 때문입니다. d
유형이 다음과 같다고 가정합니다 dict
.
# EAFP
try:
print(d['foo'])
except KeyError:
print('Not found.')
# LBYL
if 'foo' in d:
print(d['foo'])
else:
print('Not found.')
# Exceptionless "EAFP"
v = d.get('foo')
if v is None:
print('Not found.')
else:
print(v)
조사하다 추측하다쉘 명령이 성공한 경우: LBYL
때때로 우리는 쉘 스크립트에서 간단한 LBYL을 사용합니다. 이 코드는 Debian 및 Ubuntu의 기본 파일에 포함되어 .bashrc
있으며 홈 디렉터리에 .bash_aliases
. 그렇다면 이를 얻으려는 시도가 이루어집니다(현재 쉘에서 각 행을 명령으로 실행). 이는 적용 대상이기는 하지만경쟁 조건, 이 경우 발생한 오류는 아무런 해를 끼치지 않으므로 이는 매우 좋은 디자인 선택입니다.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
하지만 하위 디렉터리로 이동하여 하위 디렉터리 외부에서 실수로 수행하고 싶지 않은 작업을 수행하고 싶다고 가정해 보겠습니다. 적어도 순수한 형태의 LBYL은 좋지 않은 선택입니다. 이 경우 작업은 하나와 일치하는 여러 하위 디렉터리부터 시작하여 반복적으로 삭제하는 것입니다.전반적인 상황. (...합리적인 보안을 유지하면서 이를 수행할 수 있는 다른 방법이 많이 있기 때문에 이것은 약간 고안된 것입니다. 원한다면 실행 전 및/또는 후에 해당 디렉토리에서 더 많은 작업이 있다고 상상할 수 있습니다 rm
.)
# Don't do it this way!
if [ -d drafts ] && [ -x drafts ]; then # BAD!
cd drafts # BAD!
rm -r foo* # BAD!
fi # BAD!
drafts
여기서는 디렉터리 변경이 성공할지 확인하려고 합니다 . 나는 그것이 존재하고 디렉토리인지( -d
) 그리고 그것에 대한 실행 권한이 있는지( -x
) 확인했습니다. *nix 시스템의 디렉토리에 대해 실행 권한을 사용하면 해당 디렉토리를 변경할 수 있습니다. (대개.)
이 방법이 매우 복잡하다는 사실 외에도 문제는 내가 뭔가를 놓쳤을 수도 있다는 것입니다. 아무것도 변하지 않아도 그게 사실인가요?보장하다이 디렉토리에 들어갈 수 있나요? 내가 다 확인했나요?[이것은 독자들의 연습문제로 남겨둡니다. ]
또한, 내가 하더라도가지다모든 것을 확인하고 디렉토리가 존재하고 액세스 가능한지 확인했습니다.예전에는.이 경우 경쟁 조건이 실제로 중요합니다. 무언가 변경되어 디렉터리에 들어갈 수 없고 명령이 실패하면 그 안에 포함된 쓰레기 하위 디렉터리가 아닌 공존하는 cd
모든 귀중한 하위 디렉터리를 삭제합니다 !foo*
drafts
쉘 명령을 실행하고 작동하는지 확인하십시오.했다성공: EAFP?
이러한 고려 사항을 참고할 수 있으며몇 가지 이유Python에서 EAFP 사용:복잡하거나 읽기 어려운 코드를 사용하지 마세요.그리고상황이 바뀔 수 있는 위험~ 사이확인하고 확인에 따라 조치를 취하십시오.. 실제로 이는 위에 표시된 잘못된 접근 방식보다 더 간단하고 더 강력합니다.
if cd drafts; then
rm -r foo*
fi
cd drafts
특히 조건()이 실패할 경우 모든 것이 실패한 종료 상태가 되도록 하려는 경우 다음과 같이 작성된 것을 볼 수 있습니다.
cd drafts && rm -r foo*
이는 예외 처리와 원격으로 유사한 것을 사용하지 않습니다. 하지만 도약하기 전에는 보이지 않습니다. drafts
디렉토리가 존재하고 액세스 가능한지 여부는 확인하지 않습니다 . 단지 그것을 바꾸려고 노력하고 있을 뿐입니다. 그 다음에,시도한 후rm
, 성공 여부를 확인하고 그렇지 않은 경우 명령 실행을 계속 거부합니다.
EAFP가 예외 처리 사용을 언급하는 경우 이는 EAFP가 아닙니다. 비교가 망설여진다면 결국 이 접근 방식은 예외 처리 이전부터 있었고 C와 같은 언어에서 일반적이라는 것을 이해합니다. 그러나 이는 동일한 목표 중 일부에 의해 동기가 부여되었으며 동일한 상황의 대부분에 적용됩니다.
물론 이것은 실제로는비교적 전형적인프로그래밍에서 용서를 구하는 것은 허가의 한 형태가 아닙니다. Python은 완전히 일반적인 상황에서도 예외를 발생시키는 것이 방지되지 않기 때문에(실제로 권장됩니다) 드물습니다.
함정은 어떻습니까?
나도 어느 정도 동의한다재스의 답변. 쉘 스크립트의 트랩은 실제로 오류(명령 실패의 의미에서)를 처리하는 기본 방법은 아니지만 Python의 예외 처리와 다소 유사합니다.
그러나 쉘 스크립트의 트랩과 Python의 예외 사이에는 몇 가지 중요한 실제 차이점이 있습니다.
- Python 프로그램은 항상 예외를 사용합니다. 대부분의 쉘 스크립트는 트랩을 거의 사용하지 않습니다.
- Python 예외는 일반적으로 현재 실행 스레드 내에서 발생합니다(항상 그런 것은 아니지만). 대조적으로, 트랩은 일반적으로 비동기적으로 실행되며 다른 프로세스나 시스템에서 전송된 신호(예: Ctrl사용자가 + 를 누를 때 SIGINT C)와 같은 비동기 이벤트를 처리하는 데 주로 사용됩니다. 그러나 이러한 경우에 국한되지는 않습니다.
트랩은 쉘 스크립트의 제어 흐름에 거의 사용되지 않으며 다른 옵션을 사용할 수 있는 경우 오류 처리에 거의 사용되지 않습니다. 명령을 실행하고 작동하는지 확인하려면 확인할 수 있습니다.종료 상태. 위에 표시된 것처럼 제어 구조는 if
이를 수행하는 방법을 제공합니다.다른 사람들도 있어요).
답변2
덫쉘 스크립트의 오류 처리 기능입니까?