【问题标题】:How to have simple and double quotes in a scripted ssh command如何在脚本化 ssh 命令中使用单引号和双引号
【发布时间】:2021-02-02 21:50:48
【问题描述】:

我正在写一个小 bash 脚本,想通过 ssh 执行下面的命令

sudo -i mysql -uroot -pPASSWORD --execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"

不幸的是,这个命令同时包含单引号和双引号,所以我不能这样做

ssh user@host "command";

解决此问题的推荐方法是什么?

【问题讨论】:

    标签: linux bash ssh


    【解决方案1】:

    使用heredoc

    您可以在 shell 的标准输入上传递您的确切代码:

    ssh user@host bash -s <<'EOF'
    sudo -i mysql -uroot -pPASSWORD --execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"
    EOF
    

    请注意,上面没有执行任何变量扩展——由于使用了&lt;&lt;'EOF'(相对于&lt;&lt;EOF),它会将代码传递给远程系统完全正确,所以变量扩展 ("$foo") 将在远程端进行扩展,仅使用远程 shell 可用的变量。

    这也会消耗包含要运行的脚本的heredoc 的标准输入——如果您需要标准输入用于其他目的,这可能无法按预期工作。


    动态生成 eval-safe 命令:Array Edition

    你也可以告诉 shell 自己为你做引用。假设您的本地 shell 是 bash 或 ksh:

    #!/usr/bin/env bash
    #              ^^^^ - NOT /bin/sh
    
    # put your command into an array, honoring quoting and expansions
    cmd=(
      sudo -i mysql -uroot -pPASSWORD
        --execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"
    )
    
    # generate a string which evaluates to that array when parsed by the shell
    printf -v cmd_str '%q ' "${cmd[@]}"
    
    # pass that string to the remote host
    ssh user@host "$cmd_str"
    

    需要注意的是,如果您的字符串扩展为包含不可打印字符的值,则可在 printf '%q' 的输出中使用不可移植的 $'' 引用形式。要以可移植的方式解决这个问题,您实际上最终会使用单独的解释器,例如 Python:

    #!/bin/sh
    # This works with any POSIX-compliant shell, either locally or remotely
    # ...it *does* require Python (either 2.x or 3.x) on the local end.
    
    quote_args() { python -c '
    import pipes, shlex, sys
    quote = shlex.quote if hasattr(shlex, "quote") else pipes.quote
    sys.stdout.write(" ".join(quote(x) for x in sys.argv[1:]) + "\n")
    ' "$@"; }
    
    ssh user@host "$(quote_args sudo -i mysql -uroot -pPASSWORD sudo -i mysql -uroot -pPASSWORD)"
    

    动态生成 eval-safe 命令:Function Edition

    您还可以将命令封装在一个函数中,并告诉您的 shell 序列化该函数。

    remote_cmd() {
      sudo -i mysql -uroot -pPASSWORD --execute "select user, host, password_last_changed from mysql.user where password_last_changed <= '2016-9-00 11:00:00' order by password_last_changed ASC;"
    }
    ssh user@host bash -s <<<"$(declare -f remote_cmd); remote_cmd"
    

    如果您确定远程 shell 默认为 bash,则不需要使用 bash -s 并在此处的字符串或未引用的 heredoc 中传递代码——如果是这种情况,您可以在命令行(代替bash -s)。

    如果远程命令需要传递一些变量,使用declare -p远程设置它们,方法与上面使用declare -f相同。

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 2020-04-06
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      • 2020-07-25
      • 2018-03-19
      • 2021-09-12
      • 1970-01-01
      相关资源
      最近更新 更多