What is the need for shell when executing tclsh

2019-08-05 04:04发布

问题:

#!/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 ?

回答1:

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 use zsh :-)

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 before usr/bin.

On my system (which is locked down to my specs but no further), the script:

#!/usr/bin/env tclsh
puts $tcl_version

works just fine, outputting:

8.5

So does the script:

#!/usr/bin/tclsh
puts $tcl_version

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:

pax> cat qq.tcsh
#!/usr/bin/tclsh
puts $argc
puts $argv

pax> qq.tcsh my name is pax
4
my name is pax


回答2:

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,

 exec tclsh $0 ${1+$@} 

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.



回答3:

The reason for the two line start is to work around a 32 character line limit on the special shebang line.

#!/bin/sh
# A Tcl comment, whose contents don't matter \
exec /some/very/long/path/to/find/a/tcl/executable/path/tclsh "$0" "$@" 


回答4:

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 no tclsh in /usr/sbin, mine is in ~/.nix-profile/bin/tclsh. It also won't be appropriate for a user that has a tclsh in /usr/sbin but would prefer another version of tclsh that they put earlier in their PATH.

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:

#!/usr/bin/env tclsh

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/4ea165c5d8b126185e4bbb341e53289a0efc931d

This 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 .



标签: shell tcl