带引号的 ssh 命令

带引号的 ssh 命令

我有一个奇怪的错误,我无法找到任何相关内容。我想使用以下命令更改用户评论。

$ sudo usermod -c "New Comment" user

这将在登录到服务器时起作用,但我想在 20 多个服务器上实现自动化。通常我可以使用列表并循环访问服务器并运行命令,但在这种情况下我收到错误。

$ for i in `cat servlist` ; do echo $i ; ssh $i sudo usermod -c "New Comment" user ; done 
serv1
Usage: usermod [options] LOGIN

Options:
lists usermod options

serv2
Usage: usermod [options] LOGIN

Options:
lists usermod options
.
.
.

当我运行这个循环时,它会返回一个错误,就像我错误地使用了命令一样,但它在单个服务器上运行得很好。

查看 ssh 手册页,我确实尝试过-t-t -t标记,但这些都不起作用。

我已经成功地perl -p -i -e在类似的循环中使用来编辑文件。

有谁知道我无法循环播放的原因?

答案1

SSH 在 shell 中执行远程命令。它将字符串而不是参数列表传递给远程 shell。传递给命令的参数ssh之间用空格连接。的参数sshsudousermod-c和,因此远程 shell 会看到该命令New Commentuser

sudo usermod -c New Comment user

usermod解析Comment为用户名和user虚假的额外参数。

您需要将引号传递到远程 shell,以便将注释视为字符串。最简单的方法是将整个远程命令放在单引号中。如果您需要在该命令中使用单引号,请使用'\''.

ssh "$i" 'sudo usermod -c "Jack O'\''Brian" user'

不要循环调用并忽略错误,而是ssh使用设计用于在多个服务器上运行命令的工具,例如 pssh、mussh、clustersh 等。请参阅在许多服务器上通过 SSH 自动运行命令

答案2

for i in `cat servlist`;do echo $i;ssh $i 'sudo usermod -c "New Comment" user';done

或者

for i in `cat servlist`;do echo $i;ssh $i "sudo usermod -c \"New Comment\" user";done

答案3

您可以使用以下方便的包装脚本ssh.sh

编辑 2023/04/28。最后我找到了完美的解决方案,修复了@user202729提到的问题,但没有过度编程。

最终的 ssh 包装器是:

#!/bin/bash
args=(); for v in "$@"; do args+=("$(printf %q "$v")"); done
ssh "${args[@]}"

您可以通过复制粘贴运行来创建它:

cat <<'EOF' > ssh.sh
#!/bin/bash
args=(); for v in "$@"; do args+=("$(printf %q "$v")"); done
ssh "${args[@]}"
EOF

chmod +x ssh.sh

然后你就可以安全地通过 ssh 调用ssh.sh,而不用担心逃逸。

./ssh.sh host sudo usermod -c "New Comment" user

完整测试:

首先创建一个实用程序 /tmp/show_args.sh 显示所有参数

cat <<'EOF' > /tmp/show_args.sh
#!/bin/bash
for arg in "$@"; do echo "ARG$((++i))=${arg@Q}"; done
EOF

chmod +x /tmp/show_args.sh

进行完整测试:

./ssh.sh 127.0.0.1 -n /tmp/show_args.sh "a a" "'b b'" '"c c"' '*' '()' $'line1\nline2' $'\001    a' 'zz   '

输出是:

ARG1='a a'
ARG2=''\''b b'\'''
ARG3='"c c"'
ARG4='*'
ARG5='()'
ARG6=$'line1\nline2'
ARG7=$'\001    a'
ARG8='zz   '

您可以看到所有参数都与输入相同。笔记

''\''b b'\'''

只是字面意思

'b b'

相关内容