읽기 명령은 HEREDOC - Bash + Docker의 후속 지침을 건너뜁니다.

읽기 명령은 HEREDOC - Bash + Docker의 후속 지침을 건너뜁니다.

read문제가 발생했습니다. 쉘이나 bash가 작동하는 방식에 버그가 있는 것 같습니다. 여기서 heredoc(아마도 파일에서 제공했을 수도 있지만 테스트하지 않았음) 및 (또는 이와 유사한) 에서 제공하는 비대화형 명령을 실행합니다. ) heredoc의 명령으로 인해 read명령이 생성되었습니다. 뒤에 있는 코드는 다음과 같습니다.무시당하다, 실행이 종료됩니다오류 없음,주문 실행뒤쪽에heredoc 명령을 실행하십시오.

더 구체적으로 말하면, 여러 Linux 유틸리티의 도구 상자 역할을 하는 Docker 컨테이너에서 코드를 실행하고 있는데, 이 문제로 인해 예상한 대로 발생한다고 믿을 수 없기 때문에 실제로 안전하지 않은 코드가 생성됩니다.

이 문제의 예는 다음과 같습니다.

#!/bin/bash
set -eou pipefail

echo "before outside" >&2

docker run --rm -i ubuntu:20.04 /bin/bash <<-SHELL
    set -eou pipefail
    echo "before inside" >&2
    read 'var'
    echo "after inside" >&2
SHELL

echo "after outside" >&2

위 코드가 모든 에코를 실행하고 성공적으로 끝나거나, 명령에 오류가 발생 read하고 오류로 끝나기를 원합니다.

불행히도 위 코드의 출력은 다음과 같습니다.

before outside
before inside
after outside

read기본적으로 명령 뒤에 오는 내용을 무시합니다., 아마도 read명령에 의사 tty를 할당하지 말라는 지시가 있기 때문일 수 있습니다( docker run -it의사 tty를 할당하지만 명령의 heredoc에 대한 파이핑으로 인해 위 코드를 실행할 수 없으며 대신 오류가 발생합니다: the input device is not a TTY).

2개를 제거하면 set -eou pipefail동일한 문제가 발생합니다. 사용하더라도 read 'var' ||:(중 하나와 관련이 있다고 생각합니다.)의) set -e.

예상되는 결과의 예는 다음과 같습니다.

#!/bin/bash
set -eou pipefail

echo "before outside" >&2

docker run --rm -i ubuntu:20.04 /bin/bash <<-SHELL
    set -eou pipefail
    echo "before inside" >&2
    unknow_command error ||:
    echo "after inside" >&2
SHELL

echo "after outside" >&2

성공적으로 종료되고 다음이 인쇄됩니다.

before outside
before inside
/bin/bash: line 3: unknow_command: command not found
after inside
after outside

또는:

#!/bin/bash
set -eou pipefail

echo "before outside" >&2

docker run --rm -i ubuntu:20.04 /bin/bash <<-SHELL
    set -eou pipefail
    echo "before inside" >&2
    unknow_command error
    echo "after inside" >&2
SHELL

echo "after outside" >&2

오류로 끝나고 다음이 인쇄됩니다.

before outside
before inside
/bin/bash: line 3: unknow_command: command not found

나에게 있어 명령을 read건너뛰고(예: null 값을 입력으로 사용) 명령 이후의 모든 명령이 실행된 경우(구분된 문서에 있는 명령 포함) 오류가 발생하고 즉시 실행이 중지됩니다(도커 명령의 오류가 다음과 같은 경우). 무시하지 않음).

read위는 단지 예일 뿐이며, (또는 유사한) 명령이 직접 호출되지 않고 명령 내부에서 특정 조건에서만 호출될 수 있으므로 실제 상황은 훨씬 더 나쁠 수 있습니다 . 예를 들어:

#!/bin/bash
set -eou pipefail

docker run --rm -i my_mysql /bin/bash <<-SHELL
    set -eou pipefail
    some_important_command_1
    mysql -u "$user" -p "$pass" -e "some sql command"
    some_important_command_2
SHELL

some_important_command_after_2

위 코드는 괜찮아 보이지만 비밀번호가 비어 있으면 stdin에서 읽기를 시도하여 를 건너뛰지만 에서만 실행해야 하는 첫 번째 예에서 문제가 some_important_command_2발생 some_important_command_after_2합니다 some_important_command_2.

위의 mysql 예제는 비밀번호가 비어 있는지 확인하고 처리할 수 있는 예시일 뿐입니다.진짜 문제는 이 문제가 코드 내부에서 발생하는지 알 수 없고, 이를 피할 수 있는 안전한 방법도 보이지 않는다는 것입니다.단, Docker 도구 상자 컨테이너 사용을 중단하고 모든 호스트 내에 모든 유틸리티 및 기타 항목을 설치하고 최신 상태로 유지하십시오(컨테이너 이미지를 최신 상태로 유지하는 대신). 또한 위의 mysql 예와 같이 컨테이너 내의 서비스 내에서 구체적으로 실행되는 명령에서는 작동하지 않습니다.

위의 문제에 대한 해결책을 가진 사람이 있습니까?해결책특별히는 아니다예를 들고 있지만 해결할 수 있는 일반적인 방법이 있습니다.이런 종류의 오류(성공적으로 완료하거나, 모든 명령을 실행하거나, 오류를 발생시키고 모든 후속 명령을 중지함으로써)

고쳐 쓰다:

추가 declare -p var후 출력 echo "after inside":

before outside
before inside
declare -- var="echo \"after inside\" >&2"
after outside

@muru가 주석에서 지적했듯이 읽기 명령은 구분된 문서에서 읽는 것으로 끝나는 것 같습니다. echo "var=\$var"뒤에 추가하면 echo "after inside"다음이 인쇄되고 var=echo "after inside" >&2나도 볼 수 있습니다. 이제 구분된 문서 자체에서 해당 읽기를 건너뛰는 방법을 찾아야 합니다.

관련 정보