我试图在 bash 脚本中检查远程计算机上是否安装了某个软件包。
如果我在机器本身上执行以下语句,则文件 check.txt 中的结果为 1(已安装),这是正确的:
dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed" > /home/someuser/check.txt
但是,如果我在 SSH 会话中执行相同的命令,结果始终为 0。
有人可以解释为什么以及如何纠正这个问题吗?
谢谢。
#!/bin/bash
ADDRESS=SOMEUSER@$SOMESERVER
function run {
ssh $ADDRESS /bin/bash $@
}
run << SSHCONNECTION
dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed" > /home/someuser/check.txt
SSHCONNECTION
答案1
更改您的脚本:run << \SSHCONNECTION
或dpkg-query -W -f='\${Status}' nano
。目前,您的本地 shell 正在尝试扩展${Status}
(是的,即使它用单引号引起来),因为它位于此处文档中。 (它可能会扩展为空字符串。)
第一部分有相当详细的记录。 POSIX外壳命令语言规范,部分2.7.4 Here-文档说:
格式为…… ︙如果 有任何部分
[n]<<word
word
被引用...此处文档行不应扩展。
︙
如果没有部分word
被引用,此处文档的所有行都应扩展......
重击(1)本质上说的是同一件事。
第二部分没有那么清楚地记录。 POSIX 规范中的上述句子继续:
如果没有一部分
word
被引用时,此处文档的所有行都应扩展以进行参数扩展、命令替换和算术扩展。在这种情况下,输入中的 <backslash> 的行为与双引号内的 <backslash> 相同(请参阅双引号)。
该节还说,
这里的文档应被视为一个单词,从下一个 <newline> 开始,一直持续到有一行仅包含分隔符和 <newline>,...
相比之下,部分2.3 令牌识别说:
当io_here标记(即 a
<<
或<<-
)已被语法识别(参见外壳语法),紧接着下一个 NEWLINE 标记的一个或多个后续行形成一个或多个此处文档的主体,并应根据以下规则进行解析此处文档。当它不处理一个io_here,shell 应通过应用下面的第一个适用规则将其输入分解为令牌......
然后列出十项规则,包括
- 如果当前字符是<反斜杠>、单引号或双引号并且未加引号,则它将影响后续字符的引用,直到被引用文本的末尾。
所以我想我们需要阅读字里行间以查看此处文档中的文本几乎被视为已经在双引号中,并且已被处理仅有的用于参数扩展、命令替换和算术扩展(以及有限的反斜杠处理), 并不是用于删除报价。
另外,您应该始终引用您的 shell 变量引用(例如,"$ADDRESS"
和"$@"
),除非您有充分的理由不这样做,并且您确定您知道自己在做什么。