我有一个奇怪的错误,我无法找到任何相关内容。我想使用以下命令更改用户评论。
$ 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
之间用空格连接。的参数ssh
是sudo
、usermod
、-c
和,因此远程 shell 会看到该命令New Comment
user
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'