如何在单个SSH命令中使用bash $(awk)?

25

我正尝试通过ssh执行一个包含子代码或$(sub-code)(我经常使用它,但不知道官方名称)先在目标服务器上执行的单个命令。

举个例子,假设这是我想要使用的命令。当然,可以使用hostname,但这只是一个包含我想使用的所有格式化技巧的简化示例。

echo `uname -a | awk '{print $2}'`

没问题。但是如何正确转义并在单个命令中通过ssh发送它?以下方式是错误的,因为它会让服务器回复你的本地主机名。子代码在本地执行:

ssh myServer echo `uname -a | awk '{print $2}'`

但是任何想到的逃避方式都行不通:

$ ssh myServer echo \`uname -a | awk '{print $2}'\`
awk: cmd. line:1: {print $2}`
awk: cmd. line:1:           ^ invalid char '`' in expression
$ ssh myServer echo \$(uname -a | awk '{print $2}')
bash: syntax error near unexpected token `('
$ ssh myServer echo \$\(uname -a | awk '{print $2}')
bash: syntax error near unexpected token `)'
$ ssh myServer echo \$\(uname -a | awk '{print $2}'\)
awk: cmd. line:1: {print $2})
awk: cmd. line:1:           ^ syntax error
bash: -c: line 0: unexpected EOF while looking for matching `)'
bash: -c: line 1: syntax error: unexpected end of file

我希望你能给出一个包含正确转义的 ` 或 $() 的答案,因为我想知道是否可能。 echo` 可能会更复杂。


1
为什么要使用 echo \command`?而不是直接使用 command`? - anishsane
1
由于@anishsane想要了解如何通过ssh将反引号或$(传递到远程服务器。 - user000001
6个回答

69

试试这个

ssh myServer "uname -a | awk '{print \$2}' "

使用双引号"来组合您将远程执行的命令。

您还需要转义$$2参数,以便它不会在本地计算,而是传递给远程的awk

编辑:

如果您想包含$(),您需要再次转义$符号,如下所示:

ssh myServer "echo \$(uname -a | awk '{print \$2}') "

你也可以转义反引号 backtick,像这样:

ssh myServer "echo \`uname -a | awk '{print \$2}'\` "

@Redsandro 我想我找到了如何在ssh中转义 $( 和反引号的方法。刚刚更新了我的答案... - user000001
如果您在子命令中执行类似于 res=\ls | awk '{print \$2}'`` 的命令,我们需要两个转义符。 - coanor
1
是的,我正在尝试使用sshpass在远程服务器上执行/proc/loadavg,并使用awk过滤结果。谢谢你的回答。转义序列解决了问题!谢谢。 - Himanshu Chauhan

9

在更复杂的命令中,最好使用heredocssh一起使用,以避免在各处转义引号:

ssh -T myServer <<-'EOF'
uname -a | awk '{print $2}'
exit
EOF

5
把命令的输出通过管道传输到本地运行awk命令如何?
ssh yourhost uname -a | awk '{ print $2 } '

谢谢,这个在某些情况下可以工作。但是,为了更多的灵活性,user000001的回答正好符合我的需求。 :) - Redsandro

5

一些额外的说明:

在我的情况下,转义 $ 并不能起到帮助作用:

ts1350:> ssh sysadm@node "grep feature features.txt| awk '{print $6}' "
Password: 
A  feature   -name  ue_trace_mme    | off
ts1350:> ssh sysadm@node "grep feature features.txt| awk '{print \$6}' "
Password: 
awk: cmd. line:1: {print \}
awk: cmd. line:1:        ^ backslash not last character on line
awk: cmd. line:1: {print \}
awk: cmd. line:1:        ^ syntax error
ts1350:> ssh sysadm@node "grep feature features.txt| awk '{print \\$6}' "
Password: 
awk: cmd. line:1: {print \\}
awk: cmd. line:1:        ^ backslash not last character on line
awk: cmd. line:1: {print \\}
awk: cmd. line:1:        ^ syntax error

$和数字之间添加空格是有效的:

Fri Oct  4 14:49:28 CEST 2019
ts1350:> ssh sysadm@node "grep feature features.txt| awk '{print $ 6}' "
Password: 
off

希望这种次要的方法能够帮助像我这样的人。
感谢@dave在他的答案中提供的帮助:如何在远程ssh会话中使用awk打印特定列?

在$符号和数字之间加上一个空格是可行的,这真是太棒了,非常感谢。我尝试过 ' $,几乎所有的东西,仍然无法解决,感到沮丧。 - tom

4
解决方法是创建一个带有命令的sh文件,然后将其传递给ssh命令: test.sh
echo `uname -a | awk '{print $2}'`

命令行:

ssh myServer 'bash -s' < test.sh

更新:

没有引号的命令同样可以正常工作:

ssh myServer uname -a | awk '{print $2}'

“不带引号的命令也可以正常工作:”执行的awk是本地awk,而不是远程系统上的awk。 - anishsane
是的,所有三个问题中的命令都在管道后面正确运行。因此,唯一的解决方案是将命令保存在脚本中。 - AlecTMH
谢谢,这个可行。已点赞。但是user000001用一个命令就实现了我想要的功能,我已经接受了那个答案。 :) - Redsandro
所以唯一的解决方案就是将命令保存在脚本中。我反对使用“唯一”这个词,你可能是想说“最简单的”。 - anishsane
1
抱歉,我的意思是答案。我已经测试了user000001的最后一个命令,在远程服务器上可以运行,所以我错了。 - AlecTMH

2

如果您想获取主机名,请使用以下命令:

ssh myServer "uname -n"


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接