Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re^10: shebang anomaly

by jeffenstein (Pilgrim)
on Apr 24, 2018 at 10:02 UTC ( #1213472=note: print w/replies, xml ) Need Help??


in reply to Re^9: shebang anomaly
in thread shebang anomaly

The linked page in your other response only has this reference to the shebang line:

The shell reads its input from a file (see sh), from the -c option or from the system() and popen() functions defined in the System Interfaces volume of POSIX.1-2017. If the first line of a file of shell commands starts with the characters "#!", the results are unspecified.

The last I checked, /bin/sh on Solaris wasn't even POSIX compliant, so you can't count on that. So, to go back to the OP, I would say for maximum portability to write a bourne shell (/bin/sh) wrapper to run it, or give this snippet from perlrun a try to avoid a wrapper:

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

Replies are listed 'Best First'.
Re^11: shebang anomaly
by afoken (Canon) on Apr 24, 2018 at 22:46 UTC
    The linked page in your other response only has this reference to the shebang line

    It's a little bit hidden in 2.9.1 Simple Commands, Command Search and Execution, number 2:

    If the command name contains at least one <slash>, the shell shall execute the utility in a separate utility environment with actions equivalent to calling the execl() function defined in the System Interfaces volume of POSIX.1-2017 with the path and arg0 arguments set to the command name, and the remaining execl() arguments set to the command arguments (if any) and the null terminator.

    If the execl() function fails due to an error equivalent to the [ENOEXEC] error, the shell shall execute a command equivalent to having a shell invoked with the command name as its first operand, with any remaining arguments passed to the new shell. If the executable file is not a text file, the shell may bypass this command execution. In this case, it shall write an error message and shall return an exit status of 126.

    What happens here is this:

    1. The shell calls exec($script)
    2. The kernel reads the first few bytes of $script
    3. The kernel detects that $script starts with #!
    4. The kernel tries to execute the interpreter that follows #!, but fails.
    5. The kernel returns the ENOEXEC error to the shell (see POSIX exec)
    6. The shell now has to follow the case described above: create a new shell instance and pass it $script as the first argument.

    The rationale for this is that ancient shell scripts did not have a #! line. More details ...


    Demo:

    /tmp>echo 'echo Hello from the shell' > demo /tmp>chmod +x demo /tmp>./demo Hello from the shell /tmp>echo '#!/no/such/exe' > demo /tmp>echo 'echo Hello from the shell' >> demo /tmp>chmod +x demo /tmp>./demo -bash: ./demo: /no/such/exe: bad interpreter: No such file or director +y /tmp>chmod -x demo /tmp>./demo -bash: ./demo: Permission denied /tmp>

    Note that in the second attempt to run demo, my login shell (indicated by the leading "-") complains about the demo script specifying a bad interpreter. In the third attempt, it complains about wrong permissions on the script.

    And now, the non-obvious trick: I copied an old DOS executable (defrag.exe) to /tmp.

    /tmp>echo '#!/tmp/defrag.exe' > demo /tmp>echo 'echo Hello from the shell' >> demo /tmp>chmod +x demo /tmp>./demo -bash: ./demo: /tmp/defrag.exe: bad interpreter: Permission denied /tmp>chmod +x defrag.exe /tmp>./demo Hello from the shell /tmp>./defrag.exe -bash: ./defrag.exe: cannot execute binary file: Exec format error /tmp>

    No, my Linux did not execute defrag.exe. It can't, I don't have any emulator or the like set up for DOS executables. Bash complains if defrag.exe is not executable, but when it is executable and the kernel still had complained about an unknown executable behind the scenes, the little demo script is executed as a shell script.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

      If I understand this correctly:

      If the execl() function fails due to an error equivalent to the ENOEXEC error, the shell shall execute a command equivalent to having a shell invoked with the command name as its first operand, with any remaining arguments passed to the new shell.

      Then the shell is required to ignore the #! line if present, since the kernel already tried it and failed. However, this section of the other page you linked to hints that bash may do #! interpretation on systems that don't support #!, such as cygwin.

      So, I was completely off the mark for saying it might be in libc, but correct in the original response that it isn't the shell doing #! interpretation, since it's natively supported by macOS and Linux.

      FWIW, here is what I used to use as a template, when I was working in a shop with Solaris, HP-UX, and Linux, and I couldn't count on the system's version of perl.

      #!/bin/sh PATH=$HOME/perl/bin:$HOME/bin:$PATH export PATH exec perl -S -w -x $0 ${1+"$@"} #!perl #line 10 use 5.008; use strict; use warnings;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1213472]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (6)
As of 2019-12-07 12:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Strict and warnings: which comes first?



    Results (160 votes). Check out past polls.

    Notices?