我在 FreeBSD 机器 (xxx.yyy.zzz.net) 上运行命令并获取输出
命令
sudo camcontrol devlist | grep -o 'ada[0-9]' | while read -r a ; do sudo camcontrol identify $a | grep rotating ; done
输出
media RPM non-rotating
media RPM non-rotating
media RPM non-rotating
我正在尝试从另一台机器使用 ssh 运行相同的命令
命令
ssh xxx.yyy.zzz.net sudo camcontrol devlist | grep -o 'ada[0-9]' | while read -r a ; do sudo camcontrol identify $a | grep rotating ; done
错误
sudo: camcontrol: command not found
答案1
在您的命令中,每个命令|
都由您的本地 shell 解释。最后一个参数ssh
是devlist
。ssh
在本地调用(这并不奇怪),但第一个 之后的所有内容也是如此|
。
您收到的错误来自sudo
此代码片段:do sudo camcontrol identify $a
。它在本地运行,显然camcontrol
在本地机器上不可用。
您需要正确转义或引用。在这种情况下,您可能需要将整个远程命令括在单引号中:
ssh xxx.yyy.zzz.net 'sudo camcontrol devlist | grep -o "ada[0-9]" | while read -r a ; do sudo camcontrol identify $a | grep rotating ; done'
注意我更改了您已有的单引号。(添加的)单引号不仅将整个字符串分组以便ssh
获取它;它们还阻止了 的局部扩展$a
。
如果sudo
要要求您输入密码,则需要伪终端。您可以使用-t
选项强制分配伪终端ssh
(因此看起来像ssh -t xxx.yyy.zzz.net …
)。注意ssh -t
在远程端分配伪终端。远程sudo
提示到其 stderr,但 stdout 和 stderr 会被此伪终端“打印”(就像它们通常打印到控制台一样),此时您无法再区分它们;合并的流被捕获并传输到本地端,然后转到 stdout。如果没有-t
远程 stdout 和 stderr 单独传输,则转到本地端的 stdout 和 stderr,它们最终会合并(如果重定向则不会)成您看到的内容。这意味着-t
您无法(在本地端)区分远程 stderr 和远程 stdout。如果您需要进一步本地处理(重定向)输出并且您使用,-t
那么任何来自的提示sudo
都会干扰。
此外,您可能还想使用双引号$a
(即使在第一个不使用的命令中ssh
)。请参阅为什么我的 shell 脚本会因空格或其他特殊字符而阻塞?