Breck
Breck

Reputation: 690

How to add a hashbang to an executable Javascript file without breaking browser support?

Is it possible to have code like this:

#! /usr/local/bin/node
console.log("Hello world")

That I can also run in the browser?

I have a script that I run locally and want to run it in the browser but right now I need to "recompile" it for the browser target only to remove the hashbang line.

I can't think of a way around it. Any ideas?

Edit: my use is that I don't want to have 2 files, as I want to be able execute the current file while working on it, and also serve it via the web. I think the solution is going to have to be to either compile it for the browser to a second file or to use an alternative to #! that plays nice with javascript.

Upvotes: 1

Views: 247

Answers (1)

muru
muru

Reputation: 4897

If you only ever use bash, you can take advantage of one feature (?!) of bash: bash executes scripts without a shebang using bash. Other shells may leave it to the OS, which would usually use /bin/sh instead. For example:

bash-5.0$ echo 'echo $1 $BASH_VERSION' > foo.sh
bash-5.0$ for sh in sh bash dash ksh zsh; do $sh -c "./foo.sh $sh"; done
sh 3.2.57(1)-release
bash 5.0.7(1)-release
dash 3.2.57(1)-release
ksh
zsh 3.2.57(1)-release

(/bin/sh being a link to an old version of bash here on macOS.)

So, you could have a file like this:

///usr/local/bin/node <(tail -n +1 "$0"); exit $?
console.log("Hello world")

If you run this in a browser, or other means of running JavaScript, the first line should be ignored as a comment.

If you run this as a script in bash, the first line tells it to run ///usr/local/bin/node, using process substitution with tail to feed the rest of the file to node, and then exits:

bash-5.0$ cat foo.js
///usr/local/bin/node <(tail -n +1 "$0"); exit $?
console.log("Hello world")
bash-5.0$ ./foo.js
Hello world

This trick might work with ksh as well. The /// at the beginning of the path shouldn't cause problems - three or more / at the start of a path are equivalent to a single /.

But I would strongly encourage you to use a wrapper script instead, as suggested by the comments.

Upvotes: 1

Related Questions