node.jsbashgrepgit-bash

grep via child_process.spawn works on Git Bash for Windows, or real bash on Linux - but not both


The following code works on Windows but not on Linux (Amazon Linux 2023):

const regex = "((fa[lrsdb]\\s+|(fa-(?:solid|regular|light|thin|duotone|brands|sharp|sharp-duotone)\\s+)+)(fa-fw\\s+)*)(fa-[0-9]x\\s+)*fa(-\\w+)+"
const grep = spawn(
  'grep',
  ['-whorP', `'${regex}'`, './{classes,inc,public,tpl}'],
  { env: {...process.env, LC_ALL: 'en_US.utf8'} }
)

On Linux I get the error:

grep: /home/tdev/rentecbo/{classes,inc,public,tpl}: No such file or directory

If I add shell: true to the third argument the code works on Linux but fails on Windows with the error:

\s+)+)(fa-fw\s+)*)(fa-[0-9]x\s+)*fa(-\w+)+' was unexpected at this time.

Manually running the command via the CLI works in both environments:

grep -whorP '((fa[lrsdb]\s+|(fa-(?:solid|regular|light|thin|duotone|brands|sharp|sharp-duotone)\s+)+)(fa-fw\s+)*)(fa-[0-9]x\s+)*fa(-\w+)+' ./{classes,inc,public,tpl}

I got the script to work by setting shell: os.platform !== 'win32' but it's a bit hacky.


Solution

  • ./{classes,inc,public,tpl} is a bash syntax, which is why it doesn't work on linux without shell=true. If this is the real code, it would be easiest to just expand it manually ('./classes', './inc', './public', './tpl')

    On Windows shell=true means cmd.exe, not bash by default, which breaks down because your regexp is not escaped enough for cmd.exe

    If you insist on using bash on Windows, spawn it explicitly, i.e. spawn('bash', ['-c', 'your grep command as you'd type it'] ...