5

Task

I want to use the path returned by npm bin -g in a script.

Problem

npm bin -g returns the path then also prints to a new line that it isn't part of PATH env variable:

/home/username/.npm-global/bin
(not in PATH env variable)

To make it even more random, sometimes it prints this upgrade notice too:

 ╭─────────────────────────────────────╮
 │                                     │
 │   Update available 5.3.0 → 5.6.0    │
 │     Run npm i -g npm to update      │
 │                                     │
 ╰─────────────────────────────────────╯

These cause an error message in my script and halts its execution.

Popup error message. Nothing happens until you OK this.

What have I tried

I tried to process only the first line of the output with npm bin -g | head -n 1 but the second line still persists. I even tried npm bin -g > /dev/null but that made only the path go away, I still have the notice. What is going on?

totymedli
  • 29,531
  • 22
  • 131
  • 165

1 Answers1

4

tl;dr

Use npm bin -g 2> /dev/null

Explanation

The notice is printed to stderr. You need to redirect that to /dev/null with 2>.

If you check out the implementation of the npm bin command:

function bin (args, silent, cb) {
  if (typeof cb !== 'function') {
    cb = silent
    silent = false
  }
  var b = npm.bin
  var PATH = osenv.path()

  if (!silent) output(b)
  process.nextTick(cb.bind(this, null, b))

  if (npm.config.get('global') && PATH.indexOf(b) === -1) {
    npm.config.get('logstream').write('(not in PATH env variable)\n')
  }
}

You can see that in the end it checks if the path is in the PATH and if not, then prints the message to logstream. logstream comes from npm.config. If you check the defaults for that, you can see in this line, that it uses stderr:

logstream: process.stderr,

That is the reason why getting the first line only didn't worked, there were no second line. Also, > /dev/null redirected stdout, so you left only with the message from stderr. You can redirect stderr with 2>.

totymedli
  • 29,531
  • 22
  • 131
  • 165
  • This also means that you don't actually have to do anything special in the script to use the path. `ls -l "$(npm bin -g)"` works just fine, though it will continue to show warnings on screen. – that other guy Feb 09 '18 at 23:40
  • @thatotherguy The script runs on startup, and because there is something on stderr it popups an error message that needs to be OKd to proceed. I didn't knew this until I found the solution. – totymedli Feb 09 '18 at 23:50
  • Interesting, I've never heard of that behavior. Failing error codes definitely, but not just stderr. Which startup system is this? – that other guy Feb 09 '18 at 23:56
  • 1
    @thatotherguy It [looked like this](https://i.stack.imgur.com/7RMYh.jpg). Happens after login. This was the code at the end of `~/.profile`: `export PATH=$(npm bin -g):$PATH`. I know I can hard code it, but this is for dev laptops, the global pacakges folder path can change so it need to be dynamic. – totymedli Feb 10 '18 at 00:07