问题是选项-n / -p触发菱形运算符<> ;,它使用open的两个参数形式,因此对于文件名包含特殊字符,perl不能按预期工作:
$perl -pe '' 'uname|' Linux
或者当文件名以>开头时更危险,例如>文件.在这种情况下,文件将被截断.
要解决此问题,我们可以:
>使用CPAN的ARGV::readonly模块.
>通过自己实现像ARGV :: readonly模块这样的功能:
perl -pe 'BEGIN{$_.="\0" for @ARGV} ...' ./*
>使用-i选项,因为perl将在处理之前检查文件是否存在.
>使用-T选项启用污染模式.
我认为所有解决方案都可以解决这个问题,但也会产生副作用.如果我们可以强制perl总是使用open的参数形式,那将是一个更好的解决方案.
我想我们可以做到这一点,强迫perl总是使用开放的论证形式?
注意
这个问题仅适用于从命令行运行perl一个内联的情况,因为(当然)我们总是可以在Perl脚本中使用open的三个参数形式.
解决方法
doio.c
中的函数Perl_nextargv
是perl围绕ARGV文件句柄执行I / O的地方.
在该函数的while循环中,有两种打开文件句柄的调用.当LIKELY(PL_inplace)为真时(即,当使用-i开关运行perl时),调用是do_open_raw.当LIKELY(PL_inplace)为false时,调用是do_open6.后一个调用能够打开外部命令的管道,这通常是OP不想要的.
所以这是解决方案:在源文件doio.c中,用do_open_raw替换Perl_nextargv中的do_open6调用,并从源代码重建perl.对于perl-5.22.0,原始代码看起来像
if (LIKELY(!PL_inplace)) { if (nomagicopen ? do_open6(gv,"<",1,NULL,&GvSV(gv),1) : do_open6(gv,PL_oldname,oldlen,0) ) { return IoIFP(GvIOp(gv)); } }
if (LIKELY(!PL_inplace)) { if (do_open_raw(gv,O_RDONLY,0)) { return IoIFP(GvIOp(gv)); } }
(当您使用the new <<>>
syntax from perl 5.22.0时,nomagicopen参数为true.我想我们可以在函数顶部将其设置为true,而不必更改任何其他内容,但上面的更改是旧perl的一般解决方案).
样本输出:
$original-perl -pe '' a b c 'date|' Can't open a: No such file or directory Can't open b: No such file or directory. Can't open c: No such file or directory. Mon Sep 21 18:41:37 PDT 2015 $modified-perl -pe '' a b c 'date|' Can't open a: No such file or directory. Can't open b: No such file or directory. Can't open c: No such file or directory. Can't open date|: No such file or directory.