Linux 同时运行两个进程,并在同一终端中显示两个进程的输出

Linux 同时运行两个进程,并在同一终端中显示两个进程的输出,linux,bash,Linux,Bash,这可能吗??如果是,怎么做 我宁愿在一个终端上运行2个bash脚本,而不是在两个终端上运行 它们都需要是实时输出。请尝试以下脚本: 用法示例: # example usage: # # this runs the following commands simultaneously, each in different areas of the screen: # 1) echo hello # 2) cal # 3) for i in 1 2 3 4 5 ; do

这可能吗??如果是,怎么做

我宁愿在一个终端上运行2个bash脚本,而不是在两个终端上运行

它们都需要是实时输出。

请尝试以下脚本:

用法示例:

# example usage:
#
# this runs the following commands simultaneously, each in different areas of the screen:
#    1)   echo hello
#    2)   cal
#    3)   for i in 1 2 3 4 5 ; do date; sleep 1; done
# 
#  it waits for 2 seconds after they have all finished, before clearing the screen
#
./run_in_panes.py -s 2 'echo hello' 'cal' 'for i in 1 2 3 4 5 ; do date; sleep 1; done'
给出:

此处代码的副本,以防由于任何原因无法获得要点:

#!/usr/bin/env python

import argparse
import curses
import os
import select
import signal
import subprocess
import time


class Panes:
    """
    curses-based app that divides the screen into a number of scrollable
    panes and lets the caller write text into them
    """

    def start(self, num_panes):
        "set up the panes and initialise the app"

        # curses init
        self.num = num_panes
        self.stdscr = curses.initscr()
        curses.noecho()
        curses.cbreak()

        # split the screen into number of panes stacked vertically,
        # drawing some horizontal separator lines
        scr_height, scr_width = self.stdscr.getmaxyx()
        div_ys = [scr_height * i // self.num for i in range(1, self.num)]
        for y in div_ys:
            self.stdscr.addstr(y, 0, '-' * scr_width)
        self.stdscr.refresh()

        # 'boundaries' contains y coords of separator lines including notional
        # separator lines above and below everything, and then the panes
        # occupy the spaces between these
        boundaries = [-1] + div_ys + [scr_height]
        self.panes = []
        for i in range(self.num):
            top = boundaries[i] + 1
            bottom = boundaries[i + 1] - 1
            height = bottom - top + 1
            width = scr_width
            # create a scrollable pad for this pane, of height at least
            # 'height' (could be more to retain some scrollback history)
            pad = curses.newpad(height, width)
            pad.scrollok(True)
            self.panes.append({'pad': pad,
                               'coords': [top, 0, bottom, width],
                               'height': height})

    def write(self, pane_num, text):
        "write text to the specified pane number (from 0 to num_panes-1)"

        pane = self.panes[pane_num]
        pad = pane['pad']
        y, x = pad.getyx()
        pad.addstr(y, x, text)
        y, x = pad.getyx()
        view_top = max(y - pane['height'], 0)
        pad.refresh(view_top, 0, *pane['coords'])

    def end(self):
        "restore the original terminal behaviour"

        curses.nocbreak()
        self.stdscr.keypad(0)
        curses.echo()
        curses.endwin()



def watch_fds_in_panes(fds_by_pane, sleep_at_end=0):
    """
    Use panes to watch output from a number of fds that are writing data.
    fds_by_pane contains a list of lists of fds to watch in each pane.
    """
    panes = Panes()
    npane = len(fds_by_pane)
    panes.start(npane)
    pane_num_for_fd = {}
    active_fds = []
    data_tmpl = {}
    for pane_num, pane_fds in enumerate(fds_by_pane):
        for fd in pane_fds:
            active_fds.append(fd)
            pane_num_for_fd[fd] = pane_num
            data_tmpl[fd] = bytes()
    try:
        while active_fds:
            all_data = data_tmpl.copy()
            timeout = None
            while True:
                fds_read, _, _ = select.select(active_fds, [], [], timeout)
                timeout = 0
                if fds_read:
                    for fd in fds_read:
                        data = os.read(fd, 1)
                        if data:
                            all_data[fd] += data
                        else:
                            active_fds.remove(fd)  # saw EOF
                else:
                    # no more data ready to read
                    break
            for fd, data in all_data.items():
                if data:
                    strng = data.decode('utf-8')
                    panes.write(pane_num_for_fd[fd], strng)
        time.sleep(sleep_at_end)
    except KeyboardInterrupt:
        panes.end()
        raise

    panes.end()



def parse_args():

    parser = argparse.ArgumentParser()

    parser.add_argument("-s", "--sleep-at-end", type=float, metavar="seconds",
                        help="time to sleep for at end before clearing screen",
                        default=0.)

    parser.add_argument("commands", nargs="+", metavar="command",
                        help=("command to run in each pane "
                              "(if the command takes arguments, then quotation marks "
                              "will be needed around a command and its "
                              "arguments if invoking this from a shell)")
                        )

    return parser.parse_args()


def main():
    opts = parse_args()
    num_panes = len(opts.commands)

    procs = [subprocess.Popen(command,
                              shell=True,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE)
             for command in opts.commands]

    try:
        watch_fds_in_panes([[proc.stdout.fileno(), proc.stderr.fileno()]
                            for proc in procs],
                           sleep_at_end=opts.sleep_at_end)
    except KeyboardInterrupt:
        print("interrupted")
        for proc in procs:
            proc.send_signal(signal.SIGINT)
        time.sleep(1)
        for proc in procs:
            proc.send_signal(signal.SIGKILL)

            
if __name__ == '__main__':
    main()

作为一个便宜的解决方案和很好的工具,无论如何,你可以使用它

#终端1
./script1.sh>script1.output&
./script2.sh>script2.output&
多线程*输出
我猜multitail也可以选择从STDIN或其他文件描述符读取,但上面的示例可能是最简单的用例


更奇特的是,
tmux
和/或
screen
(或包装器/config
byobu
)可以完成这项工作,但需要了解它们的使用方法(尽管投入了大量时间)。

你的问题仍然不清楚,但是,您可以运行两个脚本或程序,与<强> GNU并行< /强>并行,并告诉它用生成的脚本的名称来标记每一行输出,并且只在断线上交错,即不在行的中间,例如:

parallel --tag --line-buffer bash ::: script1.sh script2.sh
样本输出

script1.sh  Result=0
script2.sh  Result=0
script2.sh  Result=1
script2.sh  Result=2
script2.sh  Result=3
script2.sh  Result=4
script1.sh  Result=1
script1.sh  Result=2
script1.sh  Result=3
script1.sh  Result=4
script1.sh  Result=5
script2.sh  Result=5
script1.sh  Result=6
script2.sh  Result=6
script1.sh  Result=7
script2.sh  Result=7
script1.sh  Result=8
script1.sh  Result=9
script2.sh  Result=8
script2.sh  Result=9
我使用以下脚本作为示例,将其保存为
script1.sh
script2.sh

#!/bin/bash

for ((i=0;i<10;i++)) ; do
   echo Result=$i
   sleep $((RANDOM%4))
done
   
#/bin/bash

为了((i=0;i
/script1.sh&/script2.sh&
?虽然这意味着输出将是交错的,并且它们不会是交互式的。不清楚这是否符合您的要求,因为您的描述不是很详细。您知道terminator和stuff是如何允许您拥有多个终端的吗?您可以这样做,但只运行多个终端吗终端上的脚本或函数一次就基本上分裂了它?有一些实用程序,如
screen
tmux
,这可能是您想要的。我已经考虑过这些,但如果它只是一个新的应用程序,这有点超出了我的理论观点。仍然不清楚您在问什么。“覆盖”是什么是什么意思?如果你希望得到答案,你必须更清楚地描述你的问题。