如何在脚本化的 ssh 命令中使用简单的双引号 [英] How to have simple and double quotes in a scripted ssh command

查看:21
本文介绍了如何在脚本化的 ssh 命令中使用简单的双引号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在写一个小的 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";

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

解决方案

使用 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

请注意,由于使用了 <<'EOF'(vs <<EOF),上面没有执行任何变量扩展,它将代码完全传递给远程系统,因此变量扩展("$foo")将在远程端扩展,仅使用可用于远程系统的变量远程外壳.

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


动态生成 eval-safe 命令:阵列版

您也可以告诉 shell 本身为您进行引用.假设您的本地 shell 是 bash 或 ksh:

#!/usr/bin/env bash# ^^^^ - 不是/bin/sh# 将你的命令放入一个数组中,尊重引用和扩展指令=(须藤 -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;";)# 生成一个字符串,当被 shell 解析时,该字符串的计算结果为该数组printf -v cmd_str '%q' "${cmd[@]}";# 将该字符串传递给远程主机ssh user@host "$cmd_str";

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

#!/bin/sh# 这适用于任何符合 POSIX 标准的 shell,无论是本地的还是远程的# ...它*确实*在本地端需要 Python(2.x 或 3.x).quote_args() { python -c '导入管道、shlex、sysquote = shlex.quote if hasattr(shlex, "quote") else pipe.quotesys.stdout.write(" ".join(quote(x) for x in sys.argv[1:]) + "
")' "$@";}ssh user@host "$(quote_args sudo -i mysql -uroot -pPASSWORD sudo -i mysql -uroot -pPASSWORD)";


动态生成 eval-safe 命令:函数版

您还可以将命令封装在一个函数中,并告诉您的 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"

使用 bash -s 并在 here-string 或不带引号的 heredoc 中传递代码,如果您确定远程 shell 默认为 bash -- 如果是这种情况,你可以在命令行上传递代码(代替 bash -s).

如果远程命令需要传递一些变量,使用declare -p远程设置它们,就像上面使用declare -f一样.>

I am writing a small bash script and want to execute the following command via 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;"

Unfortunately this command contains both simple and double quotes so I can't do

ssh user@host "command";

What would be the recommended way to solve this issue ?

解决方案

Using a heredoc

You can just pass your exact code on the shell's stdin:

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

Note that the above doesn't perform any variable expansions -- due to the use of <<'EOF' (vs <<EOF), it passes the code to the remote system exactly, so a variable expansion ("$foo") would be expanded on the remote side, using only variables available to the remote shell.

This also consumes stdin for the heredoc containing the script to be run -- if you need stdin to be available for other purposes, that may not work as intended.


Generating an eval-safe command dynamically: Array Edition

You can also tell the shell itself to do the quoting for you. Assuming your local shell is bash or 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"

The caveat there is that if your string expands to a value containing non-printable characters, the nonportable $'' quoting form may be used in the output of printf '%q'. To work around that in a portable manner, you actually end up using a separate interpreter such as 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:]) + "
")
' "$@"; }

ssh user@host "$(quote_args sudo -i mysql -uroot -pPASSWORD sudo -i mysql -uroot -pPASSWORD)"


Generating an eval-safe command dynamically: Function Edition

You can also encapsulate your command in a function, and tell your shell to serialize that function.

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"

Using bash -s and passing code in a here-string or unquoted heredoc isn't needed if you know with certainty that the remote shell is bash by default -- if that were the case, you could pass the code on the command line (in place of the bash -s) instead.

If the remote command needs to be passed some variables, use declare -p to set them remotely in the same way the above uses using declare -f.

这篇关于如何在脚本化的 ssh 命令中使用简单的双引号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆