인라인 실행 오류 시 bash 중단 명령을 만드는 방법

인라인 실행 오류 시 bash 중단 명령을 만드는 방법

Bash의 명령 대체(또는 인라인 실행이라고 부르는 것)를 사용하면 $()기본 명령이 실행되기 전에 텍스트가 반환될 수 있습니다. $()가 오류 코드를 반환하는 경우 기본 명령을 중단하는 방법

더 구체적으로 말하면 보조 인라인 실행 시도를 중지/방지하고 싶습니다.

Echo $(ls /devb/*) is better than $(ls /dev/*)

즉, "ls /devb/"가 0이 아닌 종료 코드를 반환하는 경우 /dev 목록을 실행하고 싶지 않습니다.

내 실제 예는 꽤 길고 구체적인 세부 사항은 질문에 그다지 중요하지 않지만 단순화된 버전은 다음과 같습니다.

Connect_to_foreign_system 1.1.1.1 /u:$(zenity <prompt for user>) /p:$(zenity <prompt for password>)

사용자 프롬프트가 취소되면 zenity는 종료 코드 1을 반환하지만 기본 명령은 계속 진행된 다음 암호를 묻는 메시지를 표시합니다.

처음에 오류 메시지가 표시되고 비밀번호를 입력하라는 메시지를 표시하고 싶지 않은 경우 Connect_to_foreign_system을 실행하지 않는 것이 가장 좋습니다.

set -e스크립트에서 실행하는 것이 아닙니다. 이는 순수한 명령줄이지만 두 번째 인라인 명령과 기본 명령이 포함된 스크립트 에 넣어도 계속 실행됩니다.

각 텍스트 문자열을 가져온 다음 명령을 실행하고 종료 코드를 테스트하는 스크립트를 작성할 수 있다는 것을 알고 있습니다. 독립형 진술로 이것을 수행하는 방법을 묻고 있습니다.

답변1

나는 그것을 할 것이다:

cmd1_output=$(cmd1) && cmd2_output=$(cmd2) &&
  printf '%s\n' "Both cmd1 and cmd2 succeeded and their output was respectively $cmd1_output and $cmd2_output"

귀하의 경우에는 다음과 같습니다.

user=$(zenity <prompt for user>) &&
  password=$(zenity <prompt for password>) &&
  Connect_to_foreign_system 1.1.1.1 /u:"$user" /p:"$password"

$(...)위의 s는 스칼라 변수 할당에 사용되기 때문에 bash에서 인용할 필요가 없지만, 위와 같이 따옴표 $user$password없는 경우 분할+glob의 영향을 받기 때문에 명령 인수에서 사용할 때 인용해야 합니다.

일반적으로 명령줄 매개 변수는 일반적으로 시스템 내에서 공개되므로( ps -Af예: 출력에 표시됨) 명령줄에서 암호를 전달하는 것은 매우 나쁜 습관입니다. 대부분의 명령에는 일반적으로 환경 변수나 일부 파일 또는 파일 설명자를 통해 비밀을 전달하는 더 안전한 방법이 있습니다.

$user한 번만 사용되는 변수 및 변수로 변수 네임스페이스를 오염시키지 않으려면 $password하위 쉘( )에서 전체 and-list를 실행할 수 있습니다 (...).

(user=$(zenity <prompt for user>) &&
  password=$(zenity <prompt for password>) &&
  Connect_to_foreign_system 1.1.1.1 /u:"$user" /p:"$password")

또는 bash에서 zsh로 전환할 수 있는 옵션이 있는 경우 변수 대신 익명 함수에 대한 위치 인수를 사용할 수 있습니다.

() {
  1=$(zenity <prompt for user>) &&
    2=$(zenity <prompt for password>) &&
    Connect_to_foreign_system 1.1.1.1 /u:$1 /p:$2
}

(zsh에서 Split+glob은 따옴표가 없는 인수에 대해 암시적 확장을 수행하지 않으므로 $1/를 따옴표로 묶을 필요가 없습니다.)$2


cmd2실패 시 실행하지 않고 ksh93, zsh 및 bash를 포함하지만 dash, busybox sh, yash 또는 mksh를 포함하지 않는 일부 셸에서 cmd1출력을 계속 사용하려면 다음 을 수행할 수도 있습니다.cmd1

printf '%s\n' "output of cmd1: $(cmd1) and of cmd2 (not run if cmd1 failed) $([ "$?" -eq 0 ] && cmd2)"

답변2

이러한 인라인 실행을 명령 대체라고 합니다. 명령의 종료 상태를 확인하려면 다른 명령 없이 명령에 해당 명령을 넣어야 하며 출력을 캡처하기 위한 할당만 하면 됩니다. 예를 들어:

if a=$(foo); then
    echo >&2 "first command failed, exiting"
    exit 1
fi
b=$(bar)
echo "output of first command: '$a', output of second: '$b'"

쉘이 glob 을 확장 하고 쉘이 제공하는 파일 이름만 인쇄하기 때문에 이것은 $(ls /dev/*)약간 어리석은 일입니다 . (다른 정보를 사용하거나 얻기 위해 사용하지 않는 한 ) glob 과 일치하는 모든 하위 디렉터리의 내용이 나열됩니다. 그럼에도 불구하고 이와 같은 문제는 다시 생각해 볼 가치가 있습니다. 첫 번째 수준의 콘텐츠만 원하는 경우 대신 또는 을 사용하세요 ./dev/*ls-l-Fls/devls /devecho /dev/*

관련 정보