如何使用 /usr/bin/env perl 功能和 perl 参数?

How to use /usr/bin/env perl functionality along with perl arguments?

我有一个带有 shebang 的 perl 脚本

#!/usr/bin/env perl

我希望此脚本在执行时打印每一行。所以我安装了 Devel::Trace 并将脚本 shebang 更改为

#!/usr/bin/env perl -d:Trace

但这会出错,因为它不是有效的语法。

我应该怎么做才能同时使用 env 功能和 tracing 功能?

首先,shebang 行的处理方式因 OS 而异。我在这里谈论的是领先的操作系统 GNU/Linux。 ;)

shebang 行将只分成两部分,解释器 (usr/bin/perl) 和第二个参数,它应该预先添加为文件名参数,它本身将在执行 shebanged 文件时自动附加。一些口译员需要那个。例如 #!/usr/bin/awk -f。文件名参数前需要-f

Perl 不需要 -f 来传递 perl 文件名,这意味着它的工作方式类似于

perl file.pl

而不是

perl -f file.pl

这基本上为您提供了可以选择一个参数开关的空间,例如

#!/usr/bin/perl -w

启用警告。此外,由于 perl 使用 getopt() 来解析命令行参数,并且 getopt() 不需要参数开关以空格分隔,所以只要不分隔它们,您甚至可以传递多个开关,如下所示:

#!/usr/bin/perl -Xw

好吧,一旦一个选项有一个值,比如 -a foo 就不再起作用,这样的选项就根本无法传递。没机会了。

更灵活的方法是使用这样的 shell 包装器:

#!/bin/bash
exec perl -a -b=123 ... filename.pl

PS:再看你的问题,你一直在问如何和/usr/bin/env perl一起使用perl开关。没有机会。如果您将选项传递给 Perl,例如 /usr/bin/env perl -w,Linux 将尝试打开解释器 'perl -w'。不再分裂。

这是 Just Doesn't Work™ 在某些系统上,尤其是带有 GNU env 的那些东西之一。

这是 perlrun 中提到的一个我过去(滥用)使用过的偷偷摸摸的解决方法:

#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS [=10=] ${1+"$@"}'
  if 0;

print "Hello, world!\n";

这会在您的 PATH 上找到 perl,您可以在命令行中添加您想要的任何其他开关。您甚至可以在调用 perl 之前设置环境变量等。一般的想法是 sh 运行 eval,但 perl 不运行,额外的粗糙位确保 Perl 正确找到您的程序并传递所有参数。

#!/bin/sh
FOO=bar; export FOO

#! -*-perl-*-
eval 'exec perl -d:Trace -x -wS [=11=] ${1+"$@"}'
  if 0;

$Devel::Trace::TRACE = 1;

print "Hello, $ENV{FOO}!\n";

如果您使用 .pl 扩展名保存文件,您的编辑器 应该 检测到正确的文件语法,但最初的 shebang 可能会将其丢弃。另一个警告是,如果脚本的 Perl 部分抛出错误,行号可能会关闭。

这个技巧的巧妙之处在于它也适用于 Ruby(可能还有一些其他语言,例如 Python,并进行了额外的修改):

#!/bin/sh
#! -*-ruby-*-
eval 'exec ruby -x -wS [=12=] ${1+"$@"}' \
  if false

puts "Hello, world!"

希望对您有所帮助!

正如@hek2mgl 评论 above,一种灵活的方法是使用 shell 包装器,因为 shebang 只接受一个参数(这将是 perl) .一个简单的包装器就是这个

#!/bin/bash

env perl -d:Trace "$@"

你可以像这样使用

#!./perltrace

或者您可以创建类似的脚本,并将它们放在 perl 所在的任何位置。

您可以使用 env-S 选项来传递参数。例如:

#!/usr/bin/env -S perl -w 

按预期工作