Search code examples
bashshgnu-screen

Sending commands to screen: limits of "stuff", quirks w/ newlines


Trying to pass a long command string to Screen via the "stuff" option. Have done this successfully in many scripts when the string is short and it exists in the in bash, like so:

screen -d -m -S worker
screen -S worker -X -p 0 stuff $'/usr/bin/env python3 /root/worker.py\n'

In this case, I am reading the command from a file. I can append '\n' to that file but the $ () constructor eats the newlines. I have tried printf, ISF=, and many permutations but where I can preserve newlines, somehow the command won't make it to screen.

GEO_COMMAND=/foo/geo_command.txt
screen -S worker -X -p 0 stuff printf '%\n' "$GEO_COMMAND"
or
screen -S worker -X -p 0 stuff $GEO_COMMAND

GEO_COMMAND: ''foo -bar -geo1 -geo2 -blah -keys ..... 160 characters later ...; /root/finish_job.sh\n '

Answer is highlighted below, adding this for posterity:

screen 'stuff' option does not like large commands and is very particular regarding newlines.

Comments / answers below solved the reliable newline issue but to paste / execute large commands, the answer is to use 'readreg' to read in a text file with the command, then pass that to screen using a second command with 'paste', as indicated below.

This approach requires no trailing newlines, does not require you to wrap your command (in the file) with quotes, and will accept conductive commands (; /foo/bar/sh) as well.


Solution

  • The screen man page suggests that stuff should not be used for large strings. As an alternative you can read a file into a register (a sort of buffer) and then paste it. Here, p is the arbitrary register:

    screen -S worker -X readreg p /foo/geo_command.txt
    screen -S worker -X paste p
    

    This more direct method has the advantage that you don't need to go via an intermediate shell variable, as in GEO_COMMAND="$(cat ...)", which loses the final newline. Also, the data is not interpreted by screen (e.g. the 2 characters \n in the file is not replaced by a 1 character newline).