Bash 기능을 러너 기능으로 래핑

Bash 기능을 러너 기능으로 래핑

내 거스크립트 에는 실행할 수 있는 mysqldump blabla > dump.sql많은 내용이 포함되어 있습니다.mysq balbla < dump.sql시운전모델.

실제로 요점은 run내가 요청하는 모든 것을 실행하는 함수를 만드는 것입니다.

  run echo 'hello world'
  run mysqldump blabla > dump.sql
  run mysql blabla < dump.sql
  run ssh blabla
  # etc


run() {
    if [[ "$(printenv DRY_RUN)" = "yes" ]]
    then
        echo "${@}"
    else
        ${@}
    fi
}

그러나 이것은 작동하지 않습니다.

run "mysqldump -uuser -ppass dbase > dump.sql"

다음 오류가 발생합니다.

mysqldump: 테이블을 찾을 수 없습니다: ">"

답변1

"${@}"대신 ${@}( with 와 같이 )을 사용해야 echo "${@}"하지만 이것이 문제의 원인은 아닙니다.

그 이유는 매개변수 대체 전, 명령줄 구문 분석 초기에 리디렉션이 발생하기 때문입니다. 따라서 변수를 >명령줄에 넣은 후에는 쉘이 더 이상 해당 변수를 찾지 않습니다 >.

답변을 게시한 후 중요한 점을 발견했습니다. 이렇게 전화하면 됩니다.

run mysqldump blabla > dump.sql

함수는 합계를 run볼 수 없습니다 . 의 출력 도 파일로 리디렉션되므로 단일 환경 변수를 사용하여 모든 리디렉션을 변경할 수 없으므로 이는 아마도 원하는 것이 아닐 것입니다 . 따라서 다음과 같은 것을 사용해야 합니다 . 아래를 참조하세요.>dump.sqlecho "${@}"run --redirect dump.sql mysqldump blabla

두 가지 가능성이 있습니다:

  1. 그것을 고수 "$@"하고 사용하십시오 eval. 물론 이는 인용의 악몽으로 이어질 수 있습니다. 따옴표 제거를 수행하기 전에 >쉘이 >명령줄에서 기본 내용을 볼 수 있도록 를 제외한 모든 항목을 따옴표로 묶어야 합니다 .

  2. 리디렉션을 개별적으로 처리합니다.

    run --redirect dump.sql mysqldump blabla
    
    run() {
        if [ "$1" == '--redirect' ]; then
            shift
            redirect_target="$1"
            shift
        else
            redirect_target='/dev/stdout' # works at least with Linux
        fi
    
        if [[ "$(printenv DRY_RUN)" = "yes" ]]
        then
            echo "${@}"
        else
            "${@}" > "$redirect_target"
        fi
    }
    

    redirect_target='/dev/stdout'if [ "$1" == '--redirect' ]의 분기에 배치하면 이를 피할 수 있습니다.elseif [[ "$(printenv DRY_RUN)" = "yes" ]]

        if [[ "$(printenv DRY_RUN)" = "yes" ]]
        then
            if [ "$1" == '--redirect' ]; then
                # do not output "--redirect file"
                shift
                shift
            fi
            echo "${@}"
        else
            if [ "$1" == '--redirect' ]; then
                shift
                redirect_target="$1"
                shift
                "${@}" > "$redirect_target"
            else
                "${@}"
            fi
        fi
    

답변2

그림최근에 게시한 또 다른 답변, 토큰화가 리디렉션을 시작하기에는 너무 늦게 발생합니다(그러나 리디렉션에 영향을 주기에는 너무 늦지는 않습니다).

eval연결된 게시물의 다른 답변에서 제안한 대로 run command 를 사용하거나 을 사용할 수 있지만 bash -c "$*"여전히 전체 명령줄(리디렉션 포함)을 인용해야 합니다.

그러나 명령을 인용하지 않으려는 경우 한 가지 옵션은 bash가 명령을 실행하지 않고 인쇄만 하도록 -nv( noexec및 )를 설정하는 것입니다. verbose따라서 run래퍼를 사용하는 대신 스크립트 시작 부분에서 다음을 수행하세요.

[[ $DRY_RUN = yes ]] && set -nv

답변3

사용 "$@"(큰따옴표 포함):

run() {
    if [[ "$(printenv DRY_RUN)" = "yes" ]]
    then
        echo "${@}"
    else
    "$@"
    fi
}

그것들이 없으면 $@단일 태그로 확장됩니다.

관련 정보