将 bash 函数包装成一个 runner 函数

sma*_*ber 1 bash

我的脚本包含许多mysqldump blabla > dump.sqlmysq 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 Code Online (Sandbox Code Playgroud)

但是,这是行不通的:

run "mysqldump -uuser -ppass dbase > dump.sql"
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

mysqldump:找不到表:">"

Hau*_*ing 5

您应该使用"${@}"而不是${@}(如 with echo "${@}"),但这不是问题的原因。

原因是重定向发生在命令行解析的早期,在参数替换之前。因此,在将变量放入>命令行后,shell 不再查找>

我在发布答案后注意到的一个重要点:通过类似的电话

run mysqldump blabla > dump.sql
Run Code Online (Sandbox Code Playgroud)

该函数run没有看到>dump.sql。这可能不是您想要的,因为它会阻止您使用单个环境变量更改所有重定向,因为 的输出echo "${@}"也会被重定向到文件。因此,你应该使用类似的东西run --redirect dump.sql mysqldump blabla,见下文。

有两种可能:

  1. 坚持"$@"使用eval。当然,这可能会让您陷入引用的噩梦。您必须引用除 the 之外的所有内容,>以便 shell>在删除引用之前在命令行中看到一个空字符。

  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
    }
    
    Run Code Online (Sandbox Code Playgroud)

    redirect_target='/dev/stdout'如果将 放在if [ "$1" == '--redirect' ]else分支中,则可以避免if [[ "$(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
    
    Run Code Online (Sandbox Code Playgroud)

  • 这个答案假定 1) 重定向将始终是输出重定向,当它可以是输入重定向时;2) 当未来的某些命令可能需要输出和输入重定向时,只需要输出重定向。 (2认同)