다음 스크립트를 만들었습니다.
# !/bin/bash # OUTPUT-COLORING red="\e[0;31m" green="\e[0;32m" NC="\e[0m" # No Color # FUNCTIONS # directoryExists - Does the directory exist? function directoryExists { cd $1 if [ $? = 0 ] then echo -e "${green}$1${NC}" else echo -e "${red}$1${NC}" fi } # EXE directoryExists "~/foobar" directoryExists "/www/html/drupal"
스크립트는 작동하지만 내 에코,
cd $1
실행 실패시 출력도 있습니다.
testscripts//test_labo3: line 11: cd: ~/foobar: No such file or directory
이것을 잡을 수 있습니까?
댓글
li>
directoryExists
입니다. 답변
스크립트가 실행되면 디렉토리가 변경됩니다. 즉, 일련의 상대 경로 이름. 그런 다음 나중에 cd
를 사용할 수있는 기능이 아니라 디렉토리 존재 만 확인하고 싶다고 주석을 달았으므로 답변은 cd
입니다. 개정. tput
및 man terminfo
의 색상 사용 :
#!/bin/bash -u # OUTPUT-COLORING red=$( tput setaf 1 ) green=$( tput setaf 2 ) NC=$( tput setaf 0 ) # or perhaps: tput sgr0 # FUNCTIONS # directoryExists - Does the directory exist? function directoryExists { # was: do the cd in a sub-shell so it doesn"t change our own PWD # was: if errmsg=$( cd -- "$1" 2>&1 ) ; then if [ -d "$1" ] ; then # was: echo "${green}$1${NC}" printf "%s\n" "${green}$1${NC}" else # was: echo "${red}$1${NC}" printf "%s\n" "${red}$1${NC}" # was: optional: printf "%s\n" "${red}$1 -- $errmsg${NC}" fi }
(편집 됨 텍스트의 이스케이프 시퀀스에 영향을 미칠 수있는 문제가있는 echo
대신 더 무적의 printf
를 사용합니다.)
댓글
- 파일 이름에 백 슬래시 문자가 포함 된 문제도 수정합니다 (xpg_echo가 켜져 있지 않은 경우).
답변
set -e
를 사용하여 오류 발생시 종료 모드를 설정합니다. 간단한 명령이 0이 아닌 상태 (실패를 나타냄)를 반환하는 경우 쉘이 종료됩니다.
set -e
가 항상 시작되는 것은 아닙니다. 테스트 위치의 명령은 실패 할 수 있습니다 (예 : if failing_command
, failing_command || fallback
). 하위 셸의 명령은 상위가 아닌 하위 셸만 종료합니다. set -e; (false); echo foo
는 foo
.
또는 bash (및 ksh 및 zsh (일반 sh는 아님), “명령이 0이 아닌 상태를 반환하는 경우 실행되는 명령을 ERR
트랩과 함께 지정할 수 있습니다 (예 : trap "err=$?; echo >&2 "Exiting on error $err"; exit $err" ERR
(false); …
와 같은 경우에는 ERR 트랩이 서브 쉘에서 실행되므로 부모를 종료 할 수 없습니다.
코멘트
- 최근 약간의 실험을 통해 트랩을 사용하지 않고 적절한 오류 처리를 쉽게 수행 할 수있는
||
동작을 수정하는 편리한 방법을 발견했습니다. 내 대답 . 그 방법에 대해 어떻게 생각하십니까? - @ sam.kozin 저는 동의합니다 ‘ 답변을 자세히 검토 할 시간이 없습니다. 원칙적으로보기 좋습니다. 이식성 외에도 ksh / bash / zsh ‘의 ERR 트랩에 비해 어떤 이점이 있습니까?
li>
ERR
의사 신호가 지원되므로 그렇게 중요하지는 않지만 완전한 POSIX 호환성 일 수 있습니다. 검토해 주셔서 감사합니다! =) 답변
@Gilles “답변 을 확장하려면 :
사실 set -e
가 작동하지 않습니다. 하위 셸에서 실행하더라도 ||
연산자를 사용하는 경우 내부 명령; 예 : 작동하지 않습니다.
#!/bin/sh # prints: # # --> outer # --> inner # ./so_1.sh: line 16: some_failed_command: command not found # <-- inner # <-- outer set -e outer() { echo "--> outer" (inner) || { exit_code=$? echo "--> cleanup" return $exit_code } echo "<-- outer" } inner() { set -e echo "--> inner" some_failed_command echo "<-- inner" } outer
하지만 ||
연산자는 정리하기 전에 외부 함수에서 복귀하는 것을 방지하는 데 필요합니다.
이 문제를 해결하는 데 사용할 수있는 약간의 트릭이 있습니다. 내부 명령을 백그라운드에서 실행 한 다음 즉시 좀 기다려.wait
내장 명령은 내부 명령의 종료 코드를 반환하며 이제는 iv id = “8a710934b9″다음에 “||
를 사용합니다. >
, 내부 함수가 아니므로set -e
는 후자 내에서 제대로 작동합니다.
#!/bin/sh # prints: # # --> outer # --> inner # ./so_2.sh: line 27: some_failed_command: command not found # --> cleanup set -e outer() { echo "--> outer" inner & wait $! || { exit_code=$? echo "--> cleanup" return $exit_code } echo "<-- outer" } inner() { set -e echo "--> inner" some_failed_command echo "<-- inner" } outer
다음은이 아이디어를 기반으로하는 일반 함수입니다. local
키워드, 즉 모든 local x=y
를 x=y
:
로 바꿉니다. # [CLEANUP=cleanup_cmd] run cmd [args...] # # `cmd` and `args...` A command to run and its arguments. # # `cleanup_cmd` A command that is called after cmd has exited, # and gets passed the same arguments as cmd. Additionally, the # following environment variables are available to that command: # # - `RUN_CMD` contains the `cmd` that was passed to `run`; # - `RUN_EXIT_CODE` contains the exit code of the command. # # If `cleanup_cmd` is set, `run` will return the exit code of that # command. Otherwise, it will return the exit code of `cmd`. # run() { local cmd="$1"; shift local exit_code=0 local e_was_set=1; if ! is_shell_attribute_set e; then set -e e_was_set=0 fi "$cmd" "$@" & wait $! || { exit_code=$? } if [ "$e_was_set" = 0 ] && is_shell_attribute_set e; then set +e fi if [ -n "$CLEANUP" ]; then RUN_CMD="$cmd" RUN_EXIT_CODE="$exit_code" "$CLEANUP" "$@" return $? fi return $exit_code } is_shell_attribute_set() { # attribute, like "x" case "$-" in *"$1"*) return 0 ;; *) return 1 ;; esac }
사용 예 :
#!/bin/sh set -e # Source the file with the definition of `run` (previous code snippet). # Alternatively, you may paste that code directly here and comment the next line. . ./utils.sh main() { echo "--> main: $@" CLEANUP=cleanup run inner "$@" echo "<-- main" } inner() { echo "--> inner: $@" sleep 0.5; if [ "$1" = "fail" ]; then oh_my_god_look_at_this fi echo "<-- inner" } cleanup() { echo "--> cleanup: $@" echo " RUN_CMD = "$RUN_CMD"" echo " RUN_EXIT_CODE = $RUN_EXIT_CODE" sleep 0.3 echo "<-- cleanup" return $RUN_EXIT_CODE } main "$@"
예제 실행 :
$ ./so_3 fail; echo "exit code: $?" --> main: fail --> inner: fail ./so_3: line 15: oh_my_god_look_at_this: command not found --> cleanup: fail RUN_CMD = "inner" RUN_EXIT_CODE = 127 <-- cleanup exit code: 127 $ ./so_3 pass; echo "exit code: $?" --> main: pass --> inner: pass <-- inner --> cleanup: pass RUN_CMD = "inner" RUN_EXIT_CODE = 0 <-- cleanup <-- main exit code: 0
이 방법을 사용할 때주의해야 할 것은 com에서 수행 된 모든 Shell 변수 수정 사항입니다. 명령이 서브 쉘에서 실행되기 때문에 run
에 전달하면 명령이 호출 함수로 전파되지 않습니다.
답변
catch
가 정확히 무슨 뜻인지 말하지 않습니다. —보고하고 계속하세요. 추가 처리를 중단 하시겠습니까?
cd
는 실패시 0이 아닌 상태를 반환하므로 다음을 수행 할 수 있습니다.
cd -- "$1" && echo OK || echo NOT_OK
실패시 간단히 종료 할 수 있습니다.
cd -- "$1" || exit 1
또는 자신의 메시지를 에코하고 종료합니다.
cd -- "$1" || { echo NOT_OK; exit 1; }
및 / 또는 실패시 cd
에서 제공 한 오류를 표시하지 않습니다.
cd -- "$1" 2>/dev/null || exit 1
표준에 따라 명령은 STDERR (파일 설명자 2)에 오류 메시지를 넣어야합니다. 따라서 2>/dev/null
는 STDERR을 /dev/null
로 알려진 “bit-bucket”으로 리디렉션합니다.
(잊지 마세요. 변수를 인용하고 cd
에 대한 옵션의 끝을 표시합니다.
댓글
- @Stephane Chazelas의 인용 및 옵션 종료 시그널링 요령은 잘 잡혔습니다. 수정 해 주셔서 감사합니다.
답변
사실 귀하의 경우에는 논리가 개선 될 수 있다고 말씀 드리고 싶습니다.
cd 대신 CD가 있는지 확인하고 존재하는지 확인한 다음 디렉토리로 이동하십시오.
if [ -d "$1" ] then printf "${green}${NC}\\n" "$1" cd -- "$1" else printf "${red}${NC}\\n" "$1" fi
하지만 가능한 오류를 차단하는 것이 목적이라면 cd -- "$1" 2>/dev/null
이지만 이는 향후 디버깅을 더 어렵게 만듭니다. if 테스트를 확인할 수 있습니다. 플래그 : 문서의 경우 배시 :
댓글
- 이 답변은
$1
변수를 인용하고 해당 변수가 공백 또는 기타 쉘 메타 문자를 포함합니다. 또한 사용자에게cd
권한이 있는지 여부도 확인하지 못합니다. - 실제로 특정 디렉터리가 있는지 확인하려고했습니다. . 하지만 ‘ 더 잘 알지 못했기 때문에 CD로 이동하려고하면 존재하지 않으면 오류가 발생할 것이라고 생각했습니다. 그러니 잡을 수 없습니까? 나는 ‘ ‘가 내가 필요한 것이 정확히 무엇인지 [-d $ 1]에 대해 알지 못했습니다. 그래서 감사합니다! (저는 ‘ Java를 프로그래밍하는 데 사용되며 if 문에서 디렉토리를 확인하는 것은 Java에서 흔하지 않습니다.)
test -d /path/to/directory
(또는 bash의[[ -d /path/to/directory ]]
)는 주어진 대상이 디렉토리인지 아닌지를 알려주며 조용히 수행합니다.cd
할 수 있는지가 아닌 디렉토리인지 테스트합니다.