如何在脚本化的 ssh 命令中使用简单的双引号 [英] How to have simple and double quotes in a scripted ssh command
问题描述
我正在写一个小的 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屋!