1

i'm trying to open a new screen for a command which using pipe. I have tried many options e.g:

screen "cat ~/input | parallel --colsep '\t' -j 100 -m sh ~/runner.sh {}"

Maybe i'm missing something with file descriptors or something, but searching efforts were in vain. Thanks.

David Barda
  • 958
  • 10
  • 28
  • 2
    `screen` accepts a single command to run; but that command can be e.g. `sh -c 'parallel .... <$HOME/input'`. (Notice also how this isn't `screen` accepting anything from a pipe, and how the useless `cat` can be avoided.) – tripleee Aug 05 '18 at 11:24
  • It does work, but just to understand, if I join those two commands using {} screen {cat ~/input | parallel --colsep '\t' -j 100 -m sh ~/runner.sh {}} why it still doesn't work? – David Barda Aug 05 '18 at 11:42
  • 2
    Not the answer to your question, but if you want to join two commands together into a compound one, you actually must have spaces surrounding the curly braces and a semi-colon after the second command, i.e. `{ command1; command2; }` – Mark Setchell Aug 05 '18 at 17:03
  • What about piped commands? – David Barda Aug 05 '18 at 17:17
  • You are making unfounded assumptions about how the shell and `screen` cooperate to parse your command line. Short answer: they don't. You cannot use shell syntax within the `screen` command line, except with a workaround like the one I showed earlier. – tripleee Aug 06 '18 at 04:39

1 Answers1

2

You cannot directly use shell syntax constructs like { code; } or ; or & or | in arguments you pass to screen (or parallel, or xargs, or etc). The shell will try to parse your command before running it, so anything which looks like

echo | moo |

will be parsed into a pipeline with the commands echo and moo and nothing (which is of course a syntax error). If you want to echo a pair of literal pipe characters, you have to quote them:

echo '| moo |'

If you want the quoted stuff to be evaluated after the shell parses it, there are a couple of options.

  • Encapsulate the command externally in a script, so that you can say screen myscript and have the actually useful commands in the script file myscript. (Some useful tools even allow you to use shell functions or even aliases here.)
  • Pass the command sh -c 'morecommands' or bash -c 'morecommands' so that the commands are quoted but end up being executed anyway. This is just another form of encapsulation really, but doesn't require a separate external definition like a script file or shell function.

So in your example, you could put your code in a script like ./metarunner and then just call screen ./metarunner; or quote the command line like

screen sh -c "parallel --colsep '\t' -j 100 -m sh $HOME/runner.sh {} <$HOME/input"

(I switched ~ to $HOME here so I could use sh instead of bash. If you need nontrivial Bash features or are too lazy to refactor your code into POSIX shell script, obviously use bash -c instead of sh -c. See also Difference between sh and bash for what the differences are exactly.)

Tangentially, I also got rid of the useless use of cat.

tripleee
  • 175,061
  • 34
  • 275
  • 318