3

Background: I'm trying to get nvm to setup up node correctly in a non-login shell via the shebang at the top of the node script.

The shebang for a node script in the login shell is:

#!/usr/bin/env node   

This doesn't work for non-login shell so I want to do the equivalent of:

#!/usr/bin/env [[ -s $HOME/.nvm/nvm.sh ]] && source "$HOME/.nvm/nvm.sh" && node

But I'm not able to get the syntax correct (see below for error). I've tried several ways, including quoting the script or trying to run it bash -c. But each time I'm facing parsing errors.

The full script is:

#!/usr/bin/env node

const semver = require('semver');
console.log("Hello World! You're using " + process.version)

Errors:

in the login shell (where I don't need it)

❯ bin/nodesample.js
env: [[: No such file or directory

in the non login shell where I want to find a solution for

env: [[: No such file or directory

If I try #!/usr/bin/env "[[ -s $HOME/.nvm/nvm.sh ]] && source "$HOME/.nvm/nvm.sh" && node"

env: "[[: No such file or directory
Preet Sangha
  • 64,563
  • 18
  • 145
  • 216
  • The shebang tells the OS what binary can run your script. So with a shebang `#!/whatever/node` you're telling your OS to run the script with the node binary. I don't think this is what you want here. You maybe still want your script to run bash commands and run nvm from bash. – Julien B. Sep 19 '22 at 00:10
  • @JulienB thanks. However, if you look at the shebang for the script, it runs the binary `/usr/bin/env` and this then runs node. It's not running node directly as in your example. Can you give an example of how I can run the inline node code from the bash script itself, please? I've added the full script I'm running. For reference without running the nvm script, node path isn't determinable. – Preet Sangha Sep 19 '22 at 00:13
  • @JulienB. See https://stackoverflow.com/questions/10376206/what-is-the-preferred-bash-shebang for what I'm talking about. – Preet Sangha Sep 19 '22 at 00:21
  • 1
    @JamesRisner - have added the error message - apologies for omitting them – Preet Sangha Sep 19 '22 at 07:24
  • 1
    Neither the shebang nor the efirst argument to `env` is an arbitrary shell command: it's the name of an executable file. – chepner Sep 19 '22 at 17:23
  • 1
    There's no cross-platform guarantee that you _can_ provide the executable on a shebang more than one argument (excluding the name of the interpreter itself, before the point where the name of the file being executed is appended), so above and beyond the limitation that it has to be an executable (not a shell command), one _also_ can't do anything too fancy just from a space-limitation perspective. – Charles Duffy Sep 19 '22 at 17:28

2 Answers2

3

The shebang is not well suited to running complex commands. It's job is just to tell the kernel what interpreter you want to use for the script. It's not executed in your shell, so concepts like [[ or && or even $parameter won't exist. In your error messages, env is telling you it wants a command it can find on your path and [[ is a bash keyword so that won't work.

The standard solution if you need to do some setup before running your command is a wrapper script, like Julien suggested.

#!/usr/bin/env bash
[[ -s $HOME/.nvm/nvm.sh ]] && source "$HOME/.nvm/nvm.sh" && node bin/nodesample.js

You could even go one step further and install a wrapper script that you can then use on the shebang line of other node scripts.

#!/usr/bin/env bash
# nodewrapper script - place in e.g. /bin
[[ -s $HOME/.nvm/nvm.sh ]] && source "$HOME/.nvm/nvm.sh" && exec node "${@}"
#!/bin/nodewrapper
const semver = require('semver');
console.log("Hello World! You're using " + process.version)
tjm3772
  • 2,346
  • 2
  • 10
1

[[: No such file or directory

Double left brackets is the built in test available in bash and zsh.

Normally test is /bin/[. But the [[ has no binary associated.

This error is reporting that it could not find [[ in your path.

#!/usr/bin/env [[ -s $HOME/.nvm/nvm.sh ]] && source "$HOME/.nvm/nvm.sh" && node

That can not work. You should reformat it this way:

#!/usr/bin/env bash

[[ -s $HOME/.nvm/nvm.sh ]] && source "$HOME/.nvm/nvm.sh" && node << EOF
const semver = require('semver');
console.log("Hello World! You're using " + process.version)
EOF

Test as working:

$ ./left
Hello World! You're using v18.9.0
James Risner
  • 5,451
  • 11
  • 25
  • 47