0

I am trying to read a string literal into stdin using the following method:

#!/usr/bin/env bash

set -e;

gmx --stdin < `cat <<EOF
   node e "console.log('foo')"
EOF`

when I run this, I get this error:

simple.sh: line 5: `cat <<EOF
   node e "console.log('foo')"
EOF`: ambiguous redirect

If I get rid of the backticks,

 gmx --stdin < cat <<EOF
       node e "console.log('foo')"
 EOF

I get this error:

/simple.sh: line 5: cat: No such file or directory

anyone know how to fix? If it's unclear what I am trying to do - I am just trying to read a string literal into the stdin of the gmx process.

I also tried this:

gmx --stdin <<<  node e "console.log('foo')"

but that didn't seem to work, I might need to put the node command in quotes, which sort defeats the purpose of what I am trying to do. I am looking to include shell variables in the command - HEREDOC is nice because I don't need to escape " characters.

2 Answers2

1

Original:

< needs files or file descriptors, while you have command-substitution there, which replaces whatever backticks are with a string of text.

For your purpose you might be better off using process substitution in bash. Something like this:

gmx --stdin < <(node e "console.log('foo')")

Or another example for clarity:

wc -l < <(df)

Edit:

To pass string literal that represents the command, you may use:

gmx --stdin <<< "$(echo node -e $'"console.log(\'foo\')"' )"

the $'...' allows for C-quoting , which is what \'foo\' part does.

Here's basically same example, but with pipe instead (which may not work if a command requires a lseekable input)

$ touch with\ space
$ echo stat $'\'with space\''
stat 'with space'
$ echo stat $'\'with space\'' | sh
  File: with space
  Size: 4096        Blocks: 8          IO Block: 4096   directory
Device: 801h/2049d  Inode: 1069455     Links: 2
Access: (0755/drwxr-xr-x)  Uid: ( 1000/     xie)   Gid: ( 1000/     xie)
Access: 2018-05-07 05:01:37.638553045 +0800
Modify: 2018-05-07 05:01:37.638553045 +0800
Change: 2018-05-07 05:01:37.638553045 +0800
 Birth: -

Additionally, there is a way to deal with quoting via printf %q, which from help printf is described as:

quote the argument in a way that can be reused as shell input

So potential solution is

printf '%q'  'node -e "conlose.log('foo')"' | gmx --stdin

or

gmx --stdin <<< "$( printf '%q'  'node -e "conlose.log('foo')"' )"
  • thanks I suspected that, can you show an example of process substitution for this case? – Alexander Mills May 06 '18 at 20:42
  • @AlexanderMills Added an example of that, plus extra one for clarity – Sergiy Kolodyazhnyy May 06 '18 at 20:46
  • Yeah, I think you might have missed what I am looking for - I am trying to send a string literal respresenting the node command to gmx stdin, not pass the stdout from the node command to the stdin of the gmx. Hope that makes sense. – Alexander Mills May 06 '18 at 20:50
  • To explain further, the gmx command will run the string literal in a subshell, so I need to pass the literal string 'node -e "console.log('foo');"' to the gmx stdin – Alexander Mills May 06 '18 at 20:51
  • This works: cat <<< "echo "444"" the problem is that I have to surround the echo command with double quotes, I am looking to avoid that so I don't have to escape the double quotes. Heredoc would allow me to avoid, but now sure how to do it. – Alexander Mills May 06 '18 at 20:58
  • @AlexanderMills So, you wanted to basically you want to echo node -e $'"console.log(\'foo\')"' and pass it to gmx --stdin ? Try that with pipe, echo node -e $'"console.log(\'foo\')"' | gmx --stdin . Alternatively, gmx --stdin <<< "$(echo node -e $'"console.log(\'foo\')"' )" – Sergiy Kolodyazhnyy May 06 '18 at 20:58
  • @AlexanderMills I've edited the answer, hopefully that helps – Sergiy Kolodyazhnyy May 06 '18 at 21:04
  • 1
    I added an answer, I think using HEREDOC is much easier to use in mose cases – Alexander Mills May 06 '18 at 21:43
1

It turns out, all I needed to do, was do this:

gmx --stdin <<EOF
   node e "console.log('foo')"
EOF

that would read the line starting with node as a string literal into the stdin of the gmx command.