由于在Windows * .csv上没有从命令行扩展到@ARGV,我通常最终会做类似的事情
map { glob } @ARGV
获取文件名。
然而,我遇到了一个异常,只是想了解真正发生的事情。我刚读完“奇怪的土地上的陌生人”,所以我可以说我没有完全理解!
use Modern::Perl;
# gets the filelist but then warns
say "Test 1 ", '-' x 20;
do { func($_) for map { glob } @ARGV } or warn "at least one arg expected\n";
say '-' x 27, "\n";
# works ok
say "Test 2 ", '-' x 20;
my @x = map { glob } @ARGV or warn "at least one arg expected\n";
func($_) for @x;
say '-' x 27, "\n";
# prints 2 (there are two files)
say "Test 3 ", '-' x 20;
func($_) for (map { glob } @ARGV or warn "at least one arg expected\n");
say '-' x 27, "\n";
sub func {
say "in func = $_[0]";
}
输出:
Test 1 --------------------
in func = t.csv
in func = t2.csv
at least one arg expected
---------------------------
Test 2 --------------------
in func = t.csv
in func = t2.csv
---------------------------
Test 3 --------------------
in func = 2
---------------------------
测试1:我不明白为什么do
没有真正返回,func
返回最后一个say
语句,返回true如果输出了什么。或者for
是否用作do
的回复?
测试3:显然隐含了一个标量上下文,但是如何?我在地图周围使用括号?
谢谢, 理查德。
答案 0 :(得分:3)
由于for
语句修饰符,第一种情况是评估false(您可能认为它是无效的)。观察:
DB<1> x do { func($_) for map { glob } @ARGV }
in func = t.csv
in func = t2.csv
0 ''
DB<2> x do { func 't.csv' ; func 't2.csv' }
in func = t.csv
in func = t2.csv
0 1
请注意,它是语句修饰符,而不是表达式修饰符。在进行这种区分的语言中,表达式具有返回值,但不具有语句。
Perl就是这样一种语言。鉴于简单的程序
#! perl
@a = (1 for 6, 7, 8);
尝试运行它会因语法错误而失败。
syntax error at foo line 2, near "1 for " Execution of foo aborted due to compilation errors.
您可以更直接地在第一次测试中表达您的意图
map func($_), map glob, @ARGV or warn "at least one arg expected\n";
给出预期的输出。
Test 1 -------------------- in func = t.csv in func = t2.csv ---------------------------
在第三种情况下,您会得到标量上下文,因为这是Perl’s logical-or定义为工作的方式。
C风格的逻辑或
二进制
||
执行短路逻辑OR运算。也就是说,如果左操作数为true,则甚至不评估右操作数。标量或列表上下文如果被计算,则向下传播到右操作数。
左操作数总是在二进制(标量)上下文中计算。整个表达式的上下文仅归于右操作数。
答案 1 :(得分:2)
保持简单,并发布可操作的便携式解决方案。
您正在查看do
的结果。
这是for
的结果,do
评估的最后一项操作,for
没有返回任何有用的内容。
您正在检查列表分配的结果。
标量上下文中的列表赋值评估其右侧(map
)返回的标量数。
您正在迭代or
返回的值。
or
返回其LHS(在标量上下文中评估)或其RHS。这将是由标量上下文(数字)中评估的map
返回的值或warn
返回的值(布尔值)。
您希望操作系统同时返回列表和数字。这不起作用。
请注意,您需要bsd_glob
,否则带有空格的路径会被破坏。 (glob
实际上使用了bsd_glob
的内容!)
use File::Glob qw( bsd_glob );
@ARGV = map bsd_glob($_), @ARGV if $^O eq 'MSWin32';
die if @ARGV < 2;
func($_) for @ARGV;