8

I have a perl script with shebang as

#!/usr/bin/env perl

I want this script to print each line as it is executed. So I installed Devel::Trace and changed script shebang to

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

But this gives error as it is not a valid syntax.

What should I do to use both env functionality and tracing functionality?

user13107
  • 3,239
  • 4
  • 34
  • 54

4 Answers4

13

This is one of those things that Just Doesn't Work™ on some systems, notably those with a GNU env.

Here's a sneaky workaround mentioned in perlrun that I've (ab)used in the past:

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

print "Hello, world!\n";

This will find perl on your PATH and you can add whatever other switches you'd like to the command line. You can even set environment variables, etc. before perl is invoked. The general idea is that sh runs the eval, but perl doesn't, and the extra gnarly bits ensure that Perl finds your program correctly and passes along all the arguments.

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

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

$Devel::Trace::TRACE = 1;

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

If you save the file with a .pl extension, your editor should detect the correct file syntax, but the initial shebang might throw it off. The other caveat is that if the Perl part of the script throws an error, the line number(s) might be off.

The neat thing about this trick is that it works for Ruby too (and possibly some other languages like Python, with additional modifications):

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

puts "Hello, world!"

Hope that helps!

Borodin
  • 126,100
  • 9
  • 70
  • 144
mwp
  • 8,217
  • 20
  • 26
2

First, the shebang line is handled differently depending on the OS. I'm talking about GNU/Linux here, the leading operating system. ;)

The shebang line will be split only in two parts, the interpreter (usr/bin/perl) and the second argument which is supposed to prepend be the filename argument which itself will be append automatically when executing the shebanged file. Some interpreters need that. Like #!/usr/bin/awk -f for example. -f is needed in front of the filename argument.

Perl doesn't need the -f to pass the perl file name, meaning it works like

perl file.pl

instead of

perl -f file.pl

That gives you basically room for one argument switch that you can choose, like

#!/usr/bin/perl -w

to enable warnings. Furthermore, since perl is using getopt() to parse the command line arguments, and getopt() does not require argument switches to be separated by spaces, you pass even multiple switches as long as you don't separate them, like this:

#!/usr/bin/perl -Xw

Well, as soon as an option takes a value, like -a foo that doesn't work any more and such options can't be passed at all. No chance.

A more flexible way is to use a shell wrappper like this:

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

PS: Looking at your question again, you have been asking how to use perl switches together with /usr/bin/env perl. No chance. If you pass an option to Perl, like /usr/bin/env perl -w, Linux would try to open the interpreter 'perl -w'. No further splitting.

hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • no other alternative apart from what you suggested? – user13107 Apr 26 '18 at 05:13
  • No, there is unfortunately no other alternative. Which OS are you using btw? (Looking for the right link to documentation) – hek2mgl Apr 26 '18 at 05:14
  • Well, actually, since Perl doesn't need the `-f`, meaning it accept a filename argument without an option, you have room for exactly one argument. – hek2mgl Apr 26 '18 at 05:21
  • I'm using Ubuntu – user13107 Apr 26 '18 at 06:21
  • The [`warnings` pragma](https://metacpan.org/pod/warnings) is more useful than the `-w` command-line option anyway, so there's another saving for the shebang-line right there. – Borodin Apr 26 '18 at 08:31
  • But the OP is asking about how switches for `env` are handled, specifically how to add `perl` switches when you're using `env` – jjmerelo Apr 26 '18 at 08:52
  • @jjmerelo That's the same principle. But when using `env` there is no room for any option – hek2mgl Apr 26 '18 at 09:00
  • @Borodin I have no idea of Perl. Was more talking about command line options in general. I was just looking for some switches that don't need a an option value. (Unfortunately `man perl` does not give me the switches) – hek2mgl Apr 26 '18 at 09:09
2

As @hek2mgl comments above, a flexible way of doing that is using a shell wrapper, since the shebang admits a single argument (which is going to be perl). A simple wraper would be this one

#!/bin/bash

env perl -d:Trace "$@"

Which you can use then like this

#!./perltrace

or you can create similar scripts, and put them wherever perl resides.

jjmerelo
  • 22,578
  • 8
  • 40
  • 86
2

You can use the -S option of env to pass arguments. For example:

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

works as expected

joanis
  • 10,635
  • 14
  • 30
  • 40
  • Doesn't universally work as expected. E.g. [on OpenBSD `env` doesn't have `-S` option](http://man.openbsd.org/env) and such an invocation complains: `env: unknown option -- S` `usage: env [-i] [name=value ...] [utility [argument ...]]` – uxer Oct 24 '22 at 20:06