将命令发送到分离的屏幕并获取输出

Rob*_*bin 14 linux ubuntu gnu-screen

我一直在寻找一种将命令发送到分离的屏幕会话的方法。到现在为止还挺好。这是我想出的:

$ screen -S test -p 0 -X stuff 'command\n'
Run Code Online (Sandbox Code Playgroud)

此命令正常工作。但是,我也想要它的输出,直接在我眼前回响(不需要.log文件或其他东西,我只想要输出)。

使用screen -L命令,不是一个选项。

Tho*_*erk 11

使用先进先出管道:

mkfifo /tmp/test
Run Code Online (Sandbox Code Playgroud)

使用重定向运算符。将命令的输出重定向到 /tmp/test 例如像这样:

screen -S test -p 0 -X stuff 'command >/tmp/test\n'
Run Code Online (Sandbox Code Playgroud)

然后在另一个外壳中

tail -f /tmp/test.
Run Code Online (Sandbox Code Playgroud)

请注意,您可能还想使用2>&1 运算符重定向错误消息。

例子

根据评论中的要求,让我们假设我们有一个 php 脚本接受用户输入并在“状态”的输入上打印服务器负载:

# cat test.php
<?php
  $fp=fopen("php://stdin","r");
  while($line=stream_get_line($fp,65535,"\n")) 
  {
    if ($line=="status") {echo "load is stub";} 
  } 
  fclose($fp);
?>
Run Code Online (Sandbox Code Playgroud)

您创建了两个 fifo:

 # mkfifo /tmp/fifoin /tmp/fifoout
Run Code Online (Sandbox Code Playgroud)

你调用一个屏幕:

screen
Run Code Online (Sandbox Code Playgroud)

在另一个控制台中,我们将其称为控制台 2,您会发现屏幕的名称:

# screen -ls
There is a screen on:
        8023.pts-3.tweedleburg  (Attached)
1 Socket in /var/run/screens/S-root.
Run Code Online (Sandbox Code Playgroud)

在控制台 2 中,您将命令发送到屏幕:

 # screen -S 8023.pts-3.tweedleburg -p 0 -X stuff 'php test.php </tmp/fifoin >/tmp/fifoout\n'
Run Code Online (Sandbox Code Playgroud)

您会看到命令出现在屏幕上。现在在控制台 2 中,您可以向 php 进程发送命令:

echo "status" >/tmp/fifoin
Run Code Online (Sandbox Code Playgroud)

并从中阅读:

# cat /tmp/fifoout
load is stub
Run Code Online (Sandbox Code Playgroud)


cha*_*ker 6

我有一个 python 脚本,它跟踪许多分离的屏幕会话并捕获每个会话的输出(当像free、top -bn2、iostat这样的利用率命令通过“stuff”定期发送时)。

而不是重定向到一个文件,因此,每个分离的屏幕会话管理至少一个文件......我只是重定向到我的父会话正在使用的任何 tty/pts。

第 1 步:在分离模式下开始一个新的屏幕会话(具有人类可读的名称)。

$ screen -dmS chad 
Run Code Online (Sandbox Code Playgroud)

步骤#2:通过东西发送你的命令(我将使用'free -g'命令和'uname -r')。使用 -p 指定要使用的窗口(在我们的例子中是第一个也是唯一的窗口)很重要。

$ screen -r chad -p0 -X stuff "free -g; uname -r" 
Run Code Online (Sandbox Code Playgroud)

第 3 步:上述步骤仅发送命令文本。我们还需要向这个分离的屏幕会话发送一个回车,让 shell 执行我们的命令。ASCII 字符 015 是大多数 *nix 系统上的回车符。

$ screen -r chad -p0 -X eval "stuff \015"
Run Code Online (Sandbox Code Playgroud)

第 4 步:将我们分离的屏幕会话的输出重定向到我们当前的 tty/pts:

$ screen -r chad -p0 -X hardcopy $(tty)
Run Code Online (Sandbox Code Playgroud)

第 4 步的输出将如下所示:

$ free -g; uname -r
             total       used       free     shared    buffers     cached
Mem:             7          1          6          0          0          0
-/+ buffers/cache:          0          7
Swap:            1          0          1
2.6.32-358.el6.x86_64
Run Code Online (Sandbox Code Playgroud)

尽管这看起来有点复杂,但该过程很容易编写脚本。使用 python,我可以解析步骤 #4 的输出并只捕获我关心的数据。

选择一个简单的场景,比如抓取 IP 细节,我写了一个示例脚本来演示上面的概念。随意更换和修补你认为合适的。

从分离的屏幕会话中获取 IP 详细信息的 Python 脚本示例:

#!/usr/bin/python

import pexpect, time

#spawn a new bash session
session = pexpect.spawn('/bin/bash')
#send screen commands
session.sendline('screen -dmS netIP')
session.sendline('screen -r netIP -p0 -X stuff "ifconfig eth0 | grep -v eth0 | head -1"')
session.sendline('screen -r netIP -p0 -X eval "stuff \\015"')
#give the command a chance to execute before reading the output of our detached screen
time.sleep(0.1)

#use the output of the uname command as our string to expect
session.sendline('screen -r netIP -p0 -X hardcopy $(tty); $(uname)')
session.expect('Linux')

#parse the output - only concerned with the 'inet' line
output = session.before.split('\n')
for o in output:
    if 'inet' in o:
        print o

#kill the screen
session.sendline('screen -r netIP -p0 -X quit')
time.sleep(0.1)

session.close()
Run Code Online (Sandbox Code Playgroud)

上面的脚本正在运行:

$ python screen-output-test.py 
      inet addr:192.168.1.201  Bcast:192.168.1.255  Mask:255.255.255.0
Run Code Online (Sandbox Code Playgroud)