3

In my Node package.json scripts, I can use some light shell syntax:

scripts: {
  detect-cheese: "echo 'Is there cheese?' $($* | grep -q cheese && echo yep || echo nope)"
}
$ yarn run detect-cheese apple cheese banana
Is there cheese? yep

But this seems to be a subset of Bash (or some other shell's) syntax. For instance, optional arguments are hard to do:

scripts: {
  fox: "echo fox $1", 
  cat: "echo cat ${1-Rufus}"
}

$ yarn run fox
Unbound argument #1
$ yarn run cat Chester
Unbound variable "1-Rufus"

Are the details of this shell-like syntax documented somewhere?

oguz ismail
  • 1
  • 16
  • 47
  • 69
Sasgorilla
  • 2,403
  • 2
  • 29
  • 56

1 Answers1

2

npm and yarn v1

The shell on unix like systems is sh so stick to POSIX sh definitions.

A default for a null or undefined value in sh is ${VAR:-default}

cat: "echo \"cat ${1:-Rufus}\""

yarn 2+ berry

Use a minimal sh implementation yarnpkg-shell which supports the basic shell syntax but is not fully POSIX compliant. This enables all environments, with or without sh, to execute package.json scripts in the same manner.


Test running the following:

printf 'VAR=  %s\n' "$VAR"
printf 'VAR-  %s\n' "${VAR-def}"
printf 'VAR:- %s\n' "${VAR:-def}"
printf 'VAR+  %s\n' "${VAR+def}"
printf 'VAR:+ %s\n' "${VAR:+def}"

via:

{
  "name": "so36729207-npm-sh",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "sh": "printf 'VAR=  %s\n' \"$VAR\"; printf 'VAR-  %s\n' \"${VAR-def}\"; printf 'VAR:- %s\n' \"${VAR:-def}\"; printf 'VAR+  %s\n' \"${VAR+def}\"; printf 'VAR:+ %s\n' \"${VAR:+def}\""
  }
}

Produces the same results for sh in dash/Debian, ash/Alpine and zsh/macos environment

$ docker run --rm so36729207/alpine npm run sh      

> so36729207-npm-sh@1.0.0 sh
> printf 'VAR=  %s
> ' "$VAR"; printf 'VAR-  %s
> ' "${VAR-def}"; printf 'VAR:- %s
> ' "${VAR:-def}"; printf 'VAR+  %s
> ' "${VAR+def}"; printf 'VAR:+ %s
> ' "${VAR:+def}"

VAR=  
VAR-  def
VAR:- def
VAR+  
VAR:+ 
$ docker run --rm --env VAR= so36729207/alpine npm run sh

> so36729207-npm-sh@1.0.0 sh
> printf 'VAR=  %s
> ' "$VAR"; printf 'VAR-  %s
> ' "${VAR-def}"; printf 'VAR:- %s
> ' "${VAR:-def}"; printf 'VAR+  %s
> ' "${VAR+def}"; printf 'VAR:+ %s
> ' "${VAR:+def}"

VAR=  
VAR-  
VAR:- def
VAR+  def
VAR:+ 
$ docker run --rm --env VAR=a so36729207/alpine npm run sh

> so36729207-npm-sh@1.0.0 sh
> printf 'VAR=  %s
> ' "$VAR"; printf 'VAR-  %s
> ' "${VAR-def}"; printf 'VAR:- %s
> ' "${VAR:-def}"; printf 'VAR+  %s
> ' "${VAR+def}"; printf 'VAR:+ %s
> ' "${VAR:+def}"

VAR=  a
VAR-  a
VAR:- a
VAR+  def
VAR:+ def
Matt
  • 68,711
  • 7
  • 155
  • 158
  • 1
    but not on windows! – Daniel A. White Oct 26 '22 at 13:53
  • 1
    Well yes, but I'm assuming OP is sane =) – Matt Oct 26 '22 at 13:57
  • Ah, cool. Actually both `${VAR:-default}` and `${VAR-default}` work in `bash` and `sh` but do slightly different things (https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html). It looks like the `:` is required in the `node` version. But it also appears to me that `node` does the same thing for `${1:-foo}` and `${1:+foo}`, which is inconsistent with `bash` and `sh`. Maybe I'm misunderstanding something here. – Sasgorilla Oct 26 '22 at 14:45
  • 2
    @Matt ideally we shouldn't answer just to the OPs question - people in the future will come here wanting to know what it is more generally. – Daniel A. White Oct 26 '22 at 15:29
  • @Sasgorilla oh right, null instead of undefined, I'll do some checking – Matt Oct 26 '22 at 23:23
  • @Sasgorilla what os/distro are you running on? it might be the flavour of `sh` that presents. – Matt Oct 26 '22 at 23:31