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

2つの可能性があります。

  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がコマンドを実行せずに印刷のみを実行するように-nvnoexecおよび)を設定することが1つあります。verboseそのため、runラッパーを使用するのではなく、スクリプトの先頭で次のようにします。

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

答え3

使用"$@"(二重引用符を含む):

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

それらがなければ、$@単一のタグに展開されます。

関連情報