perl -s switch文档混乱

cuxqih21  于 2023-10-24  发布在  Perl
关注(0)|答案(3)|浏览(115)

涉及-s switch(例如https://stackoverflow.com/a/29613573/14557599)的堆栈溢出的示例给予--的位置,如下所示:

perl -s -e 'if ($xyz) { print "$xyz\n" }' -- -xyz

perldoc perlrun

-s   enables rudimentary switch parsing for switches on the command line
     after the program name but before any filename arguments (or before
     an argument of --). Any switch found there is removed from @ARGV
     and sets the corresponding variable in the Perl program. The
     following program prints "1" if the program is invoked with a -xyz
     switch, and "abc" if it is invoked with -xyz=abc.

         #!/usr/bin/perl -s
         if ($xyz) { print "$xyz\n" }

我对“before an argument of --"感到困惑,因为上面的例子是有效的,-xyz是--之后。如果像文档中写的那样写:

perl -xyz -- -s -e 'if ($xyz) { print "$xyz\n" }' 
Can't open perl script "-s": No such file or directory

根据我对它的理解,我想在doc中写:
在程序名之后(或参数--之后),但在任何文件名参数之前
我找的钱对吗?也许在此之前的某个时候,perlrun的语法确实如文档中所描述的那样,但后来被更改,但文档被更新以反映这一点?

  • 编辑二:*

在阅读了所有的答案之后:
在程序名之后(或者如果程序是通过-e或-E开关指定的,则在--参数第一次出现之后),但在任何文件名参数之前(或者在--之前,如果程序名是第一次出现,如果程序是通过-e或-E开关指定的,则在第二次出现)

  • TL;DR*

编辑:
为了回应zdin的回答(注意:我没有找到optionswitch的定义;似乎它们是同义词,两者都被用作bash命令行参数和perl程序中的shebang行参数)。

echo a-a-a > 1.txt

q.pl

#!/usr/bin/perl -sp
s/a/b/;
if ($xyz) { print "$xyz\n" }

w.pl

#!/usr/bin/perl -s
s/a/b/;
if ($xyz) { print "$xyz\n" }

我可以调用 *.pl,传递1.txt作为参数w/out --

./q.pl -xyz=a 1.txt 
a
b-a-a

perl -p ./q.pl -xyz=a 1.txt 
a
b-a-a

单行线:

perl -spe 's/a/b/;if ($xyz) { print "$xyz\n" }' -- -xyz=a 1.txt
a
b-a-a

这表明我的重新表述对于通过程序名和一行程序运行都是有效的。
P.S.

perl --version

This is perl 5, version 34, subversion 0 (v5.34.0) built for x86_64-linux-gnu-thread-multi
h7wcgrx3

h7wcgrx31#

perldoc中引用的语句是正确的,如果不完整的话,因为它没有提到一行程序的不同行为。混淆源于存在-s的选项解析的特殊性。
该特定语句指的是运行文件中的程序,如图所示。

#!/usr/bin/perl -s

use warnings;
use strict;
use feature 'say';

our $tt;  # -s populates package variables

say $tt // "no -tt...";

我们能做

perl test_s_switch.pl -tt=X -- arguments

标记选项(“开关”)的结束,之后是参数(对于@ARGV)。如果以下参数中的第一个看起来像选项(以-开头),则需要此标记;或者我们可以忽略--(如果第一个参数不是以-开头),或者如果没有参数被传递

perl test_s_switch.pl -tt=X

这些打印X。(或者perl -s test_s_switch.pl ... w/o shebang行上的-s。)
但是对于命令行程序(“一行程序”),它会按照您观察到的方式运行

perl -s -wE'say $tt // "no -tt"' -- -tt=X

我们得到X打印。这里--是必要的,以指示选项的结束,以便在它之后进入参数。这种区别在perlrun中的命令开关开始时说明
--表示选项结束并禁止进一步的选项处理。--之后的任何参数都被视为文件名和参数。
这种差异的原因是,在文件中给出的程序的选项(“开关”)必须在程序文件名之前,留下-tt=X的位置(-s的参数)紧跟在程序文件名之后,在--或参数之前。但是使用命令行程序(“一行程序”)程序本身是选项/开关的一部分(-e'...')所以其他选项可能会跟随,所以要传递-s-tt=X)的参数,我们必须先有--,以指示选项的结束。
使用一行程序,在不使用--的情况下尝试将-tt=X转换为交换机(tt=X

perl -s -wE'say $tt // "no -tt"' -tt=X   # um, no...

并导致

Unrecognized switch: -=X  (-h will show valid options).

因为-t是合法的交换机,并且重复它(-tt)被接受。
在这一点上,我必须注意perlrun中-s开关描述末尾的一条注解
...
由于这些原因,不鼓励使用-s。请参阅Getopt::Long以获得更灵活的交换机解析。

fykwrbwg

fykwrbwg2#

首先,perl处理perl解释器的参数,以第一个--或非选项参数结束(文件名,除非你使用的是-e)。该点之后的内容填充@ARGV。然后,如果存在-s参数,则会将这些参数处理为选项,在第一个non-option或--处停止。所以你可以有两个--的示例,每个示例都发出信号停止处理一组不同的选项,一个用于perl本身,一个用于正在运行的程序。一些例子:

# No --
$ perl -s -E 'say "@ARGV"; say $c' -c a b c
-e syntax OK
# -- to stop perl option processing
$ perl -s -E 'say "@ARGV"; say $c' -- -c a b c
a b c
1
# Two --'s, one for perl options, one for -s options
# Blank line because no $c is being set (Would generate a warning
# with -w/use warnings. Does set $xyz)
$ perl -s -E 'say "@ARGV"; say $c' -- -xyz -- -c a b c
-c a b c

# ex.pl does the same as the code for the above -E option. Its presence stops
# perl option processing
$ perl -s ex.pl -c a b c
a b c
1
# -- to stop -s option processing; sets $xyz
$ perl -s ex.pl -xyz -- -c a b c
-c a b c

# With a filename starting with - so it's treated as a filename not an option
$  perl -s -- -ex.pl -c a b c
a b c
1
# And two instances of --
perl -s -- -ex.pl -- -c a b c
-c a b c
eqfvzcg8

eqfvzcg83#

它引用的是第一个--script 参数,而不是第一个--perl 参数。
假设file.pl

#!/usr/bin/perl -s

通常,一个人使用

file.pl -j             # $j = 1;

现在,假设您希望-k@ARGV中结束,而不是被视为选项。

file.pl -k             # $k = 1;  XXX

所以我们添加一个--

file.pl -- -k          # @ARGV = '-k';

组合:

file.pl -j -- -k       # $j = 1; @ARGV = '-k';

现在,如果你使用perl -se'...'代替呢?直到第一个参数不是以-开始,参数被传递给perl,而不是-s或脚本。所以你必须标记参数的结束。

perl -se'...' -i -- -j -- -k
  • -iperl处理,激活就地编辑。
  • -j-s处理,得到$j = 1
  • -k位于@ARGV中。

相关问题