【问题标题】:Variables with ssh and awk with perl带有 ssh 的变量和带有 perl 的 awk
【发布时间】:2020-05-19 05:56:15
【问题描述】:

尝试在 perl 脚本中远程执行一堆命令

看起来像这样:

    $CMD1 = "/usr/sbin/mminfo -av -q \"savetime>'-1 day 18:00:00',savetime<'17:59:59'\" -r \"ssid,totalsize,nfiles,pool\"|grep \"xxxxx\"|/usr/bin/awk '!seen[\$1]++'";
    print Dumper $CMD1;
    $CMD = "/usr/bin/ssh xxxx\@$SRV \'$CMD1\' 2>&1";
    print Dumper $CMD;

但是awk命令中的$1还是有问题,运行的时候好像取消了。

我能看到什么:

$VAR1 = '/usr/sbin/mminfo -av -q "savetime>\'-1 day 18:00:00\',savetime<\'17:59:59\'" -r "ssid,totalsize,nfiles,pool"|grep "xxxxxx"|/usr/bin/awk \'!seen[$1]++\'';
$VAR1 = '/usr/bin/ssh xxxxx@\'xxxxxx\' \'/usr/sbin/mminfo -av -q "savetime>\'-1 day 18:00:00\',savetime<\'17:59:59\'" -r "ssid,totalsize,nfiles,pool"|grep "xxxxx"|/usr/bin/awk \'!seen[$1]++\'\' 2>&1';

所以 awk 命令的 '$1' 被正确传递到远程,但是在运行时:

    @RESU = `$CMD`;
    print Dumper @RESU;

我可以看到我的 $1 丢失(或被远程 shell 解释为空值):

$VAR1 = 'awk: ligne de commande:1: !seen[]++
';
$VAR2 = 'awk: ligne de commande:1:       ^ syntax error
';
$VAR3 = 'awk: ligne de commande:1: error: expression indice non valide
';

我尝试了很多方法,例如引用或双引号字符串,使用 perl 'qq' 函数创建字符串,将 $CMD1 的值直接放入 $CMD 并转义引号但没有办法。

当然,我的 awk 通过管道传输到另一个 awk(此处未提供)。

我不想要在本地运行 awk 的解决方案,因为我从“mminfo”命令返回了数百万行。

任何线索(或更好的方法!)?

【问题讨论】:

  • 我会推荐模块Net::OpenSSH 来执行远程命令。那么你也应该能够减少所需的引用量
  • 当前的问题是 Awk 脚本中的美元符号将被远程 shell 插入。添加单个反斜杠是不够的,因为远程 shell 将执行自己的插值级别。但实际上,在管道中运行琐碎的 shell 命令是没有意义的。 Perl 本身可以很好地做到这一点。尽量减少在外部进程中运行的代码量,以降低复杂性并可能提高性能。
  • @Håkon Hægland:我无法安装 CPAN 模块...
  • @Denis.A 尝试使用perlbrew 它允许您安装没有root权限的模块。
  • @tripleee :我的大问题是 mminfo 命令返回的数据量,我不想通过网络将数百万行传输到 perl 进程。这就是我远程运行所有命令的原因,结果是一行只有 2 个字段...

标签: linux bash perl awk


【解决方案1】:

为了便于阅读,您可能希望将其分成更小的部分,并使用system 的多参数调用来避免 perl 必须生成 shell。 q() 函数在避免引用地狱方面大有帮助。

$mminfo = q{/usr/sbin/mminfo -av -q "savetime>'-1 day 18:00:00',savetime<'17:59:59'" -r "ssid,totalsize,nfiles,pool"};
$awk = q{/usr/bin/awk '/xxxxx/ && !seen[$1]++');
print Dumper [$mminfo, $awk];

@cmd = ( "/usr/bin/ssh", "xxxx\@$SRV", "$mminfo | $awk" );
print Dumper \@cmd;

system @cmd;

【讨论】:

  • 感谢您将 grep 排除在外。
  • @cmd 行有问题,我必须将 ssh 和凭证加入一个值(否则我得到:字符串在 ./charge-base1.pl 第 501 行附近的操作员预期的位置找到""/usr/bin/ssh" "user\@$SRV "") 并在连接字符串和要传递的命令之间放置一个逗号。所以它可以工作,但是由于系统不返回任何结果,我怎样才能得到我的命令的结果? (那是我使用的反引号)...尝试了 qx 函数但没有结果。
  • 缺少逗号。已编辑
  • 你会想要使用IPC::Open3 模块。
  • @Denis.A 考虑IPC::ReadpipeX 或其“另请参阅”部分中列出的任何模块。
【解决方案2】:

即使您不能在最终环境中使用模块,您也可以在本地机器上使用它们。在这种情况下,您可以使用它们以编程方式引用命令,然后将引用的字符串复制并粘贴到您正在开发的脚本中。例如:

use strict;
use warnings;
use Net::OpenSSH;

my $quoted_cmd1 = Net::OpenSSH->shell_quote('/usr/sbin/mminfo', '-av',
                       -q => q(savetime>'-1 day 18:00:00',savetime<'17:59:59'),
                       -r => 'ssid,totalsize,nfiles,pool',
                       \\'|',
                       'grep', 'xxxxx',
                       \\'|',
                       '/usr/bin/awk', '!seen[$1]++');

my $SRV = "foo";
my $quoted_cmd = Net::OpenSSH->shell_quote('/usr/bin/ssh', "xxxx\@$SRV",    
                                           $quoted_cmd1,
                                           \\'2>&1');
print "$quoted_cmd\n";

哪些输出...

/usr/bin/ssh xxxx@foo '/usr/sbin/mminfo -av -q '\''savetime>'\''\'"''"'-1 day 18:00:00'\''\'"''"',savetime<'\''\'\''17:59:59\'\'' -r ssid,totalsize,nfiles,pool | grep xxxxx | /usr/bin/awk '\''!seen[$1]++'\' 2>&1

【讨论】:

    猜你喜欢
    • 2013-07-12
    • 1970-01-01
    • 1970-01-01
    • 2020-03-03
    • 2016-01-02
    • 1970-01-01
    • 2018-12-22
    • 2021-08-05
    • 2016-01-01
    相关资源
    最近更新 更多