#!/bin/sh
# A Tcl comment, whose contents don't matter \
exec tclsh "$0" "$@"
why should we invoke shell here (#!/bin/sh) .
We can directly invoke the tclsh (#!/usr/sbin/tclsh) . Let us Assume tclsh is in sbin directoey.
Why we are First calling the shell and again inside the shell we are calling tclsh interpreter .
why people prefer to use these (#!/bin/sh , exec tclsh "$0" "$@") . Can't we execute tclsh direclty ?
The reason for the two line start is to work around a 32 character line limit on the special shebang line.
When you have a script like this, and you run it from the command line, the system thinks it is a shell script and will start to run each line as if it were a shell command.
$0 and $@ are shell variables.. $0 for tcl script path and ${1+$@} means "all the arguments, if the first argument is set" hence,
means after stopping shell, execute tclsh by passing script file (via $0) and rest arguments (via ${1+$@})
When tclsh starts, tcl variables like argv, argv will come into picture.
The main historical reason is, as @Shawn mentioned, that some old Unices couldn't handle a long shebang.
The second reason is portability in terms of system layout. Your example
#!/usr/sbin/tclsh
is an excellent example, because it won't work on my machine. There is notclsh
in/usr/sbin
, mine is in~/.nix-profile/bin/tclsh
. It also won't be appropriate for a user that has atclsh
in/usr/sbin
but would prefer another version oftclsh
that they put earlier in theirPATH
.One might think we could just use
#!tclsh
, which would solve both problems, but there are many systems still today that require an absolute path. But there's an unofficial official portable solution:This works on your average GNU/Linux distro, on cygwin/msys2 in Windows, and on all kinds of Unices since over two decades back. And it is the shebang that e.g.
tklib
uses: https://github.com/tcltk/tklib/commit/4ea165c5d8b126185e4bbb341e53289a0efc931dThis trick is so widespread and expected to work, not just for tcl but for other things too, that even NixOS, which otherwise has an empty
/usr/bin
, has a/usr/bin/env
.For more on
/usr/bin/env
and interpreters in general, see https://askubuntu.com/questions/88314/what-type-of-path-in-shebang-is-more-preferable .For more on shebangs and Tcl, see https://wiki.tcl-lang.org/page/exec+magic .
For one reason, on some systems, you can rigidly lock down what executables can be run in a shebang line. In other words, it may refuse to run anything not in
/bin
. Or maybe, if your administrators are particularly sadistic, they may try to force everyone to usezsh
:-)Secondly, this will run
tclsh
based on your current path settings. That's invaluable if you want different users to run it with different versions of TCL. Otherwise, you have to give an absolute path on the shebang line and this may be different on different systems (although/usr/bin/env
can also take care of that).It's also handy to test the scripts with more recent versions of
tclsh
before committing to them. For example, you can have tclsh 8.5 under the current latest Debian (7.1) while testing TCL 8.6 by building it in$HOME/staging/tcl86
and changing your path so that directory appears beforeusr/bin
.On my system (which is locked down to my specs but no further), the script:
works just fine, outputting:
So does the script:
although, as mentioned, it's tied to the system version of
tclsh
rather than the first one on my path.And, yes, you can get at the arguments just fine, as per the following transcript: