yet another blog

Wed, 29 Mar 2006

How arguments are passed to a shebang script

When implementing ocamlscript, I realized that argument passing for a shebang script (a Unix script starting with #!) was rather undocumented. So here is a tiny documentation of this rather contrived argument passing convention.

Suppose you have the OCaml program:

let _ =
  for i = 0 to Array.length Sys.argv  - 1 do
    Format.printf "argv(%d): \"%s\"@\n" i Sys.argv.(i)
  done
Compiled with: ocamlopt -o argv-test argv-test.ml.

And suppose you have following script-with-args shebang script:

#!./argv-test intarg1 intarg2 intarg3

and following script-without-args shebang script:

#!./argv-test

As a reference, if argv-test is called directly, you have:

$ ./argv-test arg1 arg2 arg3
argv(0): "./argv-test"
argv(1): "arg1"
argv(2): "arg2"
argv(3): "arg3"
Now, let's compare the different ways of calling the shebang script:
$ ./script-without-args 
argv(0): "./argv-test"
argv(1): "./script-without-args"

$ ./script-without-args arg1 arg2 arg3
argv(0): "./argv-test"
argv(1): "./script-without-args"
argv(2): "arg1"
argv(3): "arg2"
argv(4): "arg3"

$ ./script-with-args 
argv(0): "./argv-test"
argv(1): "intarg1 intarg2 intarg3"
argv(2): "./script-with-args"

$ ./script-with-args arg1 arg2 arg3
argv(0): "./argv-test"
argv(1): "intarg1 intarg2 intarg3"
argv(2): "./script-with-args"
argv(3): "arg1"
argv(4): "arg2"
argv(5): "arg3"

You see the pattern? :) If the shebang script is called with arguments given on the shebang line, those arguments are available in a single string as argv(1). Otherwise, argv(1) is equal to the name of the shebang script itself. If any argument in given on the command line to the shebang script, they are available as normal argument, after binary name, optional internal arguments and script name. To determine if the shebang script has internal arguments: if the called binary has at least three arguments, one should test if argv(1) is the name of an real file (and thus the script has not argument) or not (and thus the script has arguments).

As a side note, if one wants to use the env utility:

$ cat ./env-script
#!/usr/bin/env ./argv-test 

$ ./env-script 
argv(0): "./argv-test"
argv(1): "./env-script"

$ ./env-script arg1 arg2 arg3
argv(0): "./argv-test"
argv(1): "./env-script"
argv(2): "arg1"
argv(3): "arg2"
argv(4): "arg3"

However env does not support arguments on the shebang line:

$ cat ./env-script-with-args 
#!/usr/bin/env ./argv-test intarg1 intarg2 intarg3

$ ./env-script-with-args 
/usr/bin/env: ./argv-test intarg1 intarg2 intarg3: No such file or directory

2006-03-29T19:38:24Z [] permanent link

Made with PyBlosxom