向屏幕发送命令:"stuff" 的限制,带有换行符的怪癖

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

正在尝试通过“stuff”选项将长命令字符串传递给 Screen。当字符串很短且存在于 bash 中时,已在许多脚本中成功完成此操作,如下所示:

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

在这种情况下,我正在从文件中读取命令。我可以将 '\n' 附加到该文件,但 $ () 构造函数会吃掉换行符。我已经尝试过 printf、ISF= 和许多排列组合,但在我可以保留换行符的地方,命令无法显示在屏幕上。

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 '

答案在下面突出显示,为后代添加:

screen 'stuff' 选项不喜欢大命令,对换行符非常讲究。

下面的评论/答案解决了可靠的换行问题,但要粘贴/执行大型命令,答案是使用 'readreg' 通过命令读取文本文件,然后使用第二个将其传递到屏幕使用 'paste' 命令,如下所示。

这种方法不需要尾随换行符,不需要用引号将命令(在文件中)括起来,并且也将接受导电命令 (; /foo/bar/sh)。

正如您已经发现的那样,$(cmd) 会从 cmd 的输出中删除尾随换行符,并且无法阻止此行为。

但是,您可以在 $() 之后使用追加尾随换行符。

screen -S worker -X -p 0 stuff "$(cat yourFile)"$'\n'

但是,这可能会出现意外行为,因为 screen stuff 会在将 ^C\n 等控制序列输入您的会话之前对其进行解释。因此,假设文件名本身不包含任何特殊符号,获取脚本文件可能更明智:

screen -S worker -X -p 0 stuff '. yourFile\n'

screen 手册页建议 stuff 不应用于大字符串。作为替代方案,您可以将文件读入寄存器(一种缓冲区),然后将其粘贴。这里,p是任意寄存器:

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

这种更直接的方法的优点是您不需要像 GEO_COMMAND="$(cat ...)" 那样通过中间 shell 变量,它会丢失最后的换行符。此外,数据不会被 screen 解释(例如,文件中的 2 个字符 \n 不会被 1 个字符的换行符替换)。