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.