Bash: 억제 후 stderr 다시 열기

Bash: 억제 후 stderr 다시 열기

git을 자동으로 설치/제거하도록 이 스크립트를 만들었습니다. git이 설치되었는지 테스트하는 함수에서는 명령어를 사용하여 git --version반환 코드를 테스트합니다.

나는 멋진 사용자 정의 출력을 만들려고 노력하고 있기 때문에 정상적으로 발생하는 stderr 출력을 좋아하지 않습니다. 이 기능에 대해서만 stderr을 억제하는 방법을 알아냈지만 다시 활성화할 수는 없습니다.

이 함수를 호출하면 read프롬프트가 사라집니다.

function CheckGit() {
    exec 3>&2           # link file desc 3 w/ stderr
    exec 2> /dev/null

    SILENT_MODE=$1

    if [[ ! $(git --version) ]]; then
        if [ SILENT_MODE ]; then
            printf "${LT_RED} GIT IS NOT INSTALLED.\n"
        fi
        continue;
    else
        if [ SILENT_MODE ]; then
            printf "${LT_BLUE} GIT IS CURRENTLY INSTALLED.\n"
        fi
        continue;
    fi
    GIT_INSTALLED=$?
    #turn back on the stderr notifications
    exec 2>&3 3>&-      # Restore stdout and close file descriptor #3
}

while true; do
    printf "${LT_BLUE} Menu\n"
    printf " ***********************************************\n"
    printf "${LT_GREEN} a) Check git.\n"
    printf "${LT_GREEN} b) (More to be added)\n"
    printf "${LT_GREEN} c) ...\n"
    printf "${LT_GREEN} d) ...\n"
    printf "${LT_GREEN} h) ...\n"
    printf "${LT_RED} x) Exit.\n"
    printf "\n${NC}"
    read -p "Please make a selection: " eotuyx
    case $eotuyx in
        [Aa]* ) CheckGit true; continue;;
        [Bb]* ) ...; continue;;
        [Cc]* ) ...; continue;;
        [Dd]* ) ...; continue;;
        [Hh]* ) ...; continue;;
        [XxQq]* ) break;;
        * ) -e "\n${NC}" + "Please answer with a, b, c, d, x(or q).";;
    esac
done

답변1

주어진 조언을 반복한다댓글에서:

  1. continue함수에서 명령문을 제거합니다 CheckGit.
    • 그것들은 필요하지 않습니다.
    • 그리고 - 당신은 그것을 깨닫지 못할 수도 있습니다 - 이는 (함수에서) 메인 루프로 즉시 반환될 뿐만 아니라 while true메인 루프의 맨 위에 있는 명령문으로 즉시 반환됩니다. 그러므로 다음과 같이토마스는 지적했다, 귀하의 exec 2>&3 3>&-명령문이 실행되지 않았습니다.

일반 사항:

  1. if [ SILENT_MODE ]항상 옳으니까Mosvi가 지적했습니다., 문자열이 SILENT_MODE비어 있지 않은지 여부만 테스트하기 때문입니다. 당신은 을 원하는 것 같습니다 if [ "$SILENT_MODE" ].
  2. 하지만 농담일 수도 있습니다.  is가 true if [ "$SILENT_MODE" ]인 경우에도 수행하는 작업은 문자열이 null이 아닌지 테스트하는 것뿐이므로 호출하면 여전히 정보가 표시됩니다.$SILENT_MODEfalseCheckGit false
  3. 그리고 자신을 속이지 않더라도 다음 주에 이 스크립트를 유지 관리해야 하는 사람들을 속일 수도 있습니다. 그래, 그 사람이 바로 당신일 수도 있다. 귀하의 명백한 논리는 "자동 모드인 경우 추가 정보를 보고하십시오"입니다. 이는 논리적으로 반대입니다. if [ "$SILENT_MODE" = false ]변수를 말하거나 호출하는 것이 더 합리적입니다 VERBOSE_MODE.
  4. $?수명이 매우 짧습니다. 항상 이런 결과가 나오네요최근 주문들.  그래서 만약 당신이 그렇게한다면
    만약에  Git이 설치되어 있는지 확인;그 다음에
        printf "GIT가 설치되지 않았습니다.\n"
    기타
        printf "GIT가 현재 설치되어 있습니다.\n"
    필리핀 제도
    GIT_INSTALLED = $?
    그런 다음 GIT_INSTALLED종료 상태를 얻으십시오 printf. GIT_INSTALLED미리 설정해 주셔야 합니다 .
  5. 귀하의 테스트는 if [[ ! $(git --version) ]]; then"반환 코드"(귀하의 질문에서 언급한 대로)를 테스트하는 것이 아니라 git --version표준 출력에 기록되는 항목이 있는지 테스트하는 것입니다. 이것이 당신이 원하는 것일 수도 있습니다. 이것이 git설치되었는지 테스트하는 가장 좋은 방법 일 것입니다 . 그러나 명령의 종료 상태를 확인하는 것이 더 나을 수도 있습니다(보통 더 나을 수도 있습니다).
  6. 스타일 참고: if"진짜" 부분이 먼저 오면 진술을 이해하기가 더 쉽습니다 then. else귀하의 스크립트는 다음과 같이 말합니다
    Git이 설치되지 않은 경우
    그 다음에
        설치되어 있지 않다고 하네요
    그렇지 않은 경우(즉,아니요설치되지 않음)
        이미 설치됐다고 하네요
    필리핀 제도
    이중 부정은 혼란스럽습니다.
  7. 그리고 그렇습니다. exec 2> /dev/null42개의 연속된 명령문에 대한 표준 오류를 억제하려는 경우 편리합니다. 단일 명령에만 영향을 주어야 하는 경우 다음과 같이 해당 명령에 2> /dev/null (또는 )를 입력하면 됩니다.> /dev/null 2>&1좀 더 나은 제안.

답변2

명령이 좋아 보이지만 논리가 모든 경우를 포괄하지는 않습니다. continue실행 시 설명자는 반전되지 않습니다 .

또한 작동 방식과 실제로 작동하는 방식을 분석하십시오.

GIT_INSTALLED=$?

$?마지막으로 실행된 명령의 종료 코드입니다. 디버깅을 사용하여 이를 더 자세히 살펴보세요( set -x).

또한 초보자는 정적 테스트 스크립트를 통해 큰 이점을 얻을 수 있습니다.shellcheck.net.

관련 정보