Bash Script – Fix Issues with NPM Commands

bashenvironment-variablesshell-script

I have a script that runs some git and npm commands based on a user like

#!/bin/sh
/bin/su someuser -c "
cd /opt/app1/;
env -i git remote update;
env -i git pull origin dev;
cd /opt/app1/client/;
npm run build;
"

The git commands run correctly. The npm command runs and builds the files but throws lots of errors about

Node Sass could not find a binding for your current environment: Linux 64-bit with Node.js 8.x

Found bindings for the following environments:
  - Linux 64-bit with Node.js 9.x

This usually happens because your environment has changed since running `npm install`.
Run `npm rebuild node-sass --force` to build the binding for your current environment.

If I run npm run build as the user from terminal, everything builds fine. I even tried env -i npm run build in the script and that just says env: ‘npm’: No such file or directory. So i then tried env -i /usr/local/bin/npm run build and oddly that returned /usr/bin/env: 'node': No such file or directory.

I though that the user -c would set me up with all env like the user was logged in and that env -i would give me clean env without the parent.

also tried:

#!/bin/sh
/bin/su someuser - -c "
cd /opt/app1/;
git remote update;
git pull origin dev;
cd /opt/app1/client/;
npm run build;
"

That last attempt returns same as first: git commands work, build throws errors about sass and environment as if something is different than when i run the command as the user from the terminal.

Any idea why this command is not working correctly?

Best Answer

env -i cleans the environment, and that includes the PATH variable, which is used to look up commands if you don't give the full path. So, with env -i, you need to specify the full path to commands being invoked. With npm, what probably happens is that npm itself is a script which has #! /usr/bin/env node as the shebang, so the lookup for the node command fails.

If you need to clean the environment, try either of:

  • sudo -iu someuser sh -c "...."
  • su someuser - -c "...." (both these commands start login shells with some cleaning of the environment)
  • or, with env, retain some environment variables, like the Ubuntu service command does:

    $ grep env $(command -v service) -m1
    out=$(env -i LANG="$LANG" LANGUAGE="$LANGUAGE" LC_CTYPE="$LC_CTYPE" LC_NUMERIC="$LC_NUMERIC" LC_TIME="$LC_TIME" LC_COLLATE="$LC_COLLATE" LC_MONETARY="$LC_MONETARY" LC_MESSAGES="$LC_MESSAGES" LC_PAPER="$LC_PAPER" LC_NAME="$LC_NAME" LC_ADDRESS="$LC_ADDRESS" LC_TELEPHONE="$LC_TELEPHONE" LC_MEASUREMENT="$LC_MEASUREMENT" LC_IDENTIFICATION="$LC_IDENTIFICATION" LC_ALL="$LC_ALL" PATH="$PATH" TERM="$TERM" "$SERVICEDIR/$SERVICE" status 2>&1)
    

    You probably don't need all those, but keep $PATH, $TERM, and maybe set LC_ALL=C.

Related Question