【问题标题】:SSH Command in bashbash 中的 SSH 命令
【发布时间】:2020-03-06 12:29:38
【问题描述】:

在 ssh 会话期间我们不工作但在 ubuntu 机器上手动运行时工作正常的这些命令需要一些帮助。

for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done

不知何故,上面的代码不起作用,它应该有这样的输出:

var
123
asd
123
dsa
123
123
123

相反,我是这样的:

123
123
123
123
<blank space>
<blank space>
<blank space>
<blank space>

这里是完整的代码:

ssh -o "StrictHostKeyChecking no" -i $PEM_PATH $SERVER_USER@$SERVER_IP << EOF
    for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

非常感谢任何帮助,谢谢!

【问题讨论】:

标签: bash ssh


【解决方案1】:

问题在于本地 shell 在将 $ 表达式发送到 ssh 会话之前对其进行了插值。你可以通过单引号来防止这种情况发生:'EOF'

ssh -o "StrictHostKeyChecking no" -i $PEM_PATH $SERVER_USER@$SERVER_IP <<'EOF'
    for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

使用上面的代码,$(echo "/var/asd/dsa/123" | tr "/" " ") ; 被发送到服务器而不是被本地替换。

【讨论】:

  • 另外,现在我仔细观察,$w 也正在被替换(可能什么都没有)。 “EOF”也将纠正这一点。
  • 在这种情况下,$w 被插入空字符串是问题所在,$(echo "/var/asd/dsa/123" | tr "/" " ") 在本地或远程执行的结果相同。
【解决方案2】:

您的方法存在几个问题:

您的 here 文档在本地进行插值。您正在运行的实际命令是:for w in var asd dsa 123 ; do echo &gt;&amp;2; echo "123"; done

您可以通过使用 set -x 来启用本地跟踪,并使用 cat 而不是登录 shell 运行 ssh:

ssh pi cat << EOF
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

+ ssh pi cat
++ echo /var/asd/dsa/123
++ tr / ' '
for w in  var asd dsa 123 ; do echo  >&2; echo "123"; done

如您所见,echo /var/asd/dsa/123tr / ' ' 在本地执行,$w 被插入到空字符串中。

您可能希望在 'EOF' 周围使用单引号:

ssh pi cat << 'EOF'
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

+ ssh pi cat
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done

现在,命令正确到达那里。

注意:如果您希望$(echo "/var/asd/dsa/123" | tr "/" " ") 在本地运行,那么您至少需要转义$w。

ssh pi << EOF
    for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo \$w >&2; echo "123"; done
EOF

缓冲会打乱顺序。这就是为什么您的空行(由echo &gt;&amp;2 打印的行)位于输出的末尾。您可以使用tee 来“强制”行缓冲:

ssh -T pi << 'EOF'
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done
EOF

+ ssh -T pi
Linux mserv 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l
... 

123
123
123
123
var
asd
dsa
123

对比:

ssh pi << 'EOF'
for w in $(echo "/var/asd/dsa/123" | tr "/" " ") ; do echo $w >&2; echo "123"; done 2>&1 | tee
EOF

+ ssh pi
Linux mserv 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l
...
var
123
asd
123
dsa
123
123
123

(在第一种情况下,首先打印 STDIN,然后是 STDERR,在第二种情况下,行交替)

管道命令到 ssh 并强制登录 shell 如果您通过将命令通过管道传输到 ssh 的标准输入来运行命令,它将运行一个登录 shell 并打印 MOTD(取决于服务器配置)并运行一个登录 shell(它有几个副作用)。

在我的示例中,Linux mserv 3.10.25+ #622 PREEMPT Fri Jan 3 18:41:00 GMT 2014 armv6l 是 MOTD 的一部分。但是,不需要管道,ssh 将通过用户 shell 运行最后一个参数,而不需要将其通过管道传输到 STDIN。这可能仅限于 MAX_ARG_STRLEN(约为 128K),但如果您有一个这么大的脚本,您可能应该先 scp-it 到主机。

$ ssh pi '
for w in $(echo "/var/asd/dsa/123" | tr "/" " ")
do
   echo $w >&2
   echo "123"
done 2>&1 | tee
'
var
123
asd
123
dsa
123
123
123

注意:这可能仅限于 MAX_ARG_STRLEN(约为 128K),但如果您有这样大小的脚本,您可能应该先 scp-it 到主机。

注意: pi 是我使用的测试服务器,请将其替换为您的适当连接信息。

【讨论】:

    猜你喜欢
    • 2013-05-29
    • 2013-10-03
    • 1970-01-01
    • 2016-11-15
    • 2017-10-05
    • 1970-01-01
    • 2016-11-09
    • 2021-01-28
    • 2013-07-14
    相关资源
    最近更新 更多