如何将命令通过管道传输到任何终端?

JMC*_*125 4 terminal pipe tty command fifo

我经常一次使用多个终端(或终端模拟器);虽然在 XI 中可以复制粘贴命令,除了不太实用之外,它显然不适用于真正的 TTY。我想到的第一个想法是相似的:

command > /dev/sometty
Run Code Online (Sandbox Code Playgroud)

不幸的是,command在运行之前,它是管道,并没有像花样echo `command`会的工作,不管有多少个奇怪的bash字符($`"等)的存在。所以/dev/sometty简单地获取一些文本。

问题是,有时,我什至值得将这些命令通过管道传输到文件中,使其可执行等,或者很快:制作脚本并从适当的终端运行它。但这是很多工作。我一直在考虑制作一个脚本来制作这些文件,以获取说明:

termpipe -e "command1\ncommand2\"command 1 argument\\n(s)\"" -t /dev/sometty 
Run Code Online (Sandbox Code Playgroud)

它会做类似的事情:

  1. 管道命令,例如, /tmp/termpipe-20140208-153029-1.sh
  2. 使文件可执行
  3. 在适当的终端中运行文件
  4. 执行完成后删除脚本

AFAIK,问题出在3.:这不能解决任何问题,因为我需要另一个termpipe实例来在适当的终端上运行第一个实例。一个为那个。另一个是,无限期所以这是行不通的。或者可以吗?...

解决方案可能是为每个终端使用一个命名管道,当每个终端启动时,脚本会告诉管道将它接收到的任何内容转发到终端,然后执行它(就像某种守护进程)。

我认为这可能有效,但我不知道如何设置初始脚本。我怎样才能?如何告诉 FIFO 为各个终端提供管道命令以运行?我不太了解 Bash,所以我很感激完整的解释。

JMC*_*125 5

之后,您可以很好地制定您的最后一个计划。为了使要发送的命令不被 shell 处理,它在到达管道时必须是字符串的形式(因此echo "command",不是echo `command`)。然后,它必须通过一个后台进程中读取(一个守护进程,但不一定)开始在相应的终端。它应该通过相同的过程进行评估

但是每个管道都有一个脚本是很老套的。因此,让我们将编写脚本概括为term-pipe-r.sh(不要忘记chmod +x!):

#!/bin/bash

pipe=$1                     # the pipe name is the first argument
trap 'rm -f "$pipe"' EXIT     # ignore exit and delete messages until the end

if [[ ! -p $pipe ]]; then   # if the pipe doesn't exist, create it
    mkfifo $pipe
fi

while true                  # cycle eternally..
do
    if read line <$ pipe; then
        if [[ "$line" == 'close the term-pipe pipe' ]]; then
            break
            # if the pipe closing message is received, break the while cycle
        fi

        echo                # a line break should be used because of the prompt 
        eval $line          # run the line: as this script should be started
    fi                          # in the target terminal, 
done                            # the line will be run there.

echo "<pipe closing message>"   # custom message on the end of the script
Run Code Online (Sandbox Code Playgroud)

所以说你想/dev/tty3接收命令:去那里,做

./term-pipe-r.sh tty3pipe &     # $1 will be tty3pipe (in a new process)
Run Code Online (Sandbox Code Playgroud)

并从任何终端(甚至从它自己)发送命令:

echo "command" > tty3pipe
Run Code Online (Sandbox Code Playgroud)

或者在那里运行一个文件:

cat some-script.sh > tty3pipe
Run Code Online (Sandbox Code Playgroud)

请注意,此管道会忽略诸如.bashrc和其中的别名之类的文件,例如alias ls='ls --color'. 希望这可以帮助那里的人。

编辑(注意 - 非守护进程的优势):

上面我谈到了管道读取器不一定是守护进程,但实际上,我检查了差异,结果证明在这种情况下仅作为后台进程更好。因为这样,当您关闭终端时,脚本也会收到EXIT信号(SIGHUPSIGTERM或其他任何东西),然后trap自动删除管道(请参阅脚本中以开头的行),避免无用的进程和文件(如果有这样的重定向到无用的管道,也许还有其他人)。

编辑(自动化):

尽管如此,在大多数情况下必须运行您(至少是我)可能想要的脚本还是很无聊的。所以,让我们自动化吧!它应该任何终端开始,并且所有人都阅读的一件事是.bashrc. 另外,必须使用./term-pipe-r.sh. 因此,可以这样做:

cd /bin # go to /bin, where Bash gets command names
ln -s /directory/of/term-pipe-r.sh tpr  # call it tpr (terminal pipe reader)
Run Code Online (Sandbox Code Playgroud)

现在要运行它,你只需要tpr tty3pipe &/dev/tty3你想要的时候。但是,当您可以自动完成时,为什么要这样做呢?所以这应该添加到.bashrc. 但是等等:它如何知道管道名称?它可以基于 TTY 名称(可以通过tty命令知道),使用简单的REGEX in sed(和一些 技巧)。您应该添加的内容~/.bashrc将是:

pipe="$(sed 's/\/dev\///' <<< `tty` | sed 's/\///')pipe"
                # ^^^- take out '/dev/' and other '/', add 'pipe'
tpr $pipe &     # start our script with the appropriate pipe name
Run Code Online (Sandbox Code Playgroud)