在Perl脚本内外使用Shell命令的结果不同

3

我有一个perl脚本,需要检查远程机器上的一个空目录。使用ksh,我可以让以下shell脚本工作:

ksh# ssh user@host '[ "$(ls -A /empty/dir/* 2>/dev/null)" ] && echo "1" || echo "0"'

如果目录为空或不存在,这将正确返回“0”。只有当目录包含内容时,它才会返回“1”。

但是,当我在Perl脚本中像这样放置此行:

#!/usr/bin/perl
print `ssh user\@host '[ "$(ls -A /empty/dir/* 2>/dev/null)" ] && echo "1" || echo "0"'`

无论我在其中放什么,它都会返回“1”,即使目录为空也是如此。我已经检查了与普通shell和perl脚本相比的env值,它们是相同的。
有人有任何想法为什么这个命令只在perl脚本中返回不同的结果吗?
两台机器都是AIX 6.1,默认shell为KSH。

1
Perl 可能在调用 /bin/sh。你尝试过直接调用 ksh 吗?/bin/ksh ssh user… - sidyll
我已经尝试过了。无论我指定bash还是ksh,都会出现错误“ksh:test:0403-021缺少一个]字符。” - Scott M
命令中的$(...)部分应该在远程主机上运行。本地主机使用sh或ksh都无所谓。 - mob
2个回答

2

反引号内的文本在传递给操作系统之前被视为在双引号内插值。运行

print qq`ssh user\@host '[ "$(ls -A /empty/dir/* 2>/dev/null)" ] && echo "1" || echo "0"'`

为了确切地查看传递给操作系统的字符串,我敢打赌你至少得转义 $

一种更安全、更明智的方法是先构建你的命令,然后在后面用反引号运行它:

# q{...} does no interpolation
my $cmd = q{ssh user\@host '[ "$(ls -A /empty/dir/* 2>/dev/null)" ] && echo "1" || echo "0"'};
print `$cmd`;

谢谢。你说得对,在使用“qq”后,我发现以下内容实际上被发送到了操作系统:“[ "0 11 10 8 7 3 2 0ls -A /empty/dir* 2>/dev/null)" ]”。你能解释一下q{}的作用是什么,为什么它更安全吗? - Scott M
与单引号字符串一样,q{...}不会插值其内容。请参阅perlop中的类似引用运算符 - mob

0
use Net::SFTP::Foreign;

my $s = Net::SFTP::Foreign->new('user@host');
my $empty = 1;
if (my $d = $s->opendir('/empty/dir')) {
  if (defined $s->readdir($d)) {
    $empty = 0
  }
}

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