#! with multiple args

Today I ran into the fact that shebangs with multiple arguments do not get parsed as I would expect…

In order to prevent multiple copies of a long-running cronjob from running simultaneously I wanted to use flock. So I changed the first line of my script.

#!/bin/bash

My standard above, to something that I would expect to work.

#!/usr/bin/flock --nonblock /tmp/mylockfile /bin/bash

Running it gave me:

/usr/bin/flock: unrecognized option '--nonblock /tmp/mylockfile /bin/bash'

Followed by flock’s usage information…

Not exactly what I was hoping for. After a bit of duck-ducking I found some helpful information[1,2] which taught me the following:

  • The shebang is used by the kernel to call the correct interpreter if the leading magic bits of the file are “!#”
  • Most historic kernels used to only pass the first 32 bytes of the line, Linux uses 127. So watch that character count!
  • Only the first space is used to separate the command from the argument, all trailing spaces are ignored and passed as a single argument, essentially an exec('prog', 'arg1 arg2 arg3')
  • Perl parses its arguments as it pleases, and doesn’t let the exec string tell it what to do.

I ended up with the following, which while it works was a bit too ugly for me to commit for others to review:

#!/usr/bin/perl -e exec "/usr/bin/flock", "--nonblock", "/tmp/mylockfile", "/bin/bash", @ARGV

I also have a simple program as a perl gist, simply because I haven’t touched perl in years, so if I need to in the future my shebangs can be a bit simpler.

#!/bin/spacexec /usr/bin/flock --nonblock /tmp/mylockfile /bin/bash
#! with multiple args