How can I pipe commands to any terminal?
Following this, one can very well make that last plan of yours work. For the command to-be-sent not to be processed by the shell, it has to be in the form of a string when reaches the pipe (thus echo "command"
, not echo `command`
). Then it has to be read by a background process (alike a daemon, but not necessarily) started in the appropriate terminal. It should be evaluated by the same process.
But it is boiler-platey to have a script per pipe. So let's generalize making a script as term-pipe-r.sh
(don't forget to chmod +x
it!):
#!/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
So say you want /dev/tty3
to receive commands: just go there, do
./term-pipe-r.sh tty3pipe & # $1 will be tty3pipe (in a new process)
And to send commands, from any terminal (even from itself):
echo "command" > tty3pipe
or to run a file there:
cat some-script.sh > tty3pipe
Note this piping ignores files like .bashrc
, and the aliases in there, such as alias ls='ls --color'
. Hope this helps someone out there.
Edit (note - advantage of non-daemon):
Above I talked about the pipe reader not being a daemon necessarily, but in fact, I checked the differences, and it turns out it is way better to be a mere background process in this case. Because this way, when you close the terminal, an EXIT
signal (SIGHUP
, SIGTERM
, or whatever) is received by the script as well, and the pipe is deleted then (see the line starting with trap
in the script) automatically, avoiding a useless process and file (and maybe others if there were such redirecting to the useless pipe).
Edit (automation):
Still, it is boring to have to run a script you (I, at least) probably want most of the time. So, let's automatize it! It should start in any terminal, and one thing all of them read is .bashrc
. Plus, it sucks to have to use ./term-pipe-r.sh
. So, one may do:
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)
Now to run it you'd only need tpr tty3pipe &
in /dev/tty3
whenever you'd want. But why do that when you can have it done automatically? So this should be added to .bashrc
. But wait: how will it know the pipe name? It can base the name on the TTY (which can be know with the tty
command), using simple REGEX's in sed
(and some tricks). What you should add to ~/.bashrc
will then be:
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
Related videos on Youtube
Ievgen Chuchukalo
There's no lack of reasons to stop using SE...
Updated on September 18, 2022Comments
-
Ievgen Chuchukalo over 1 year
I often use more than one terminal (or terminal emulator) at a time; and while in X I can copy-paste commands, besides not being very practical, it obviously does not work on the real TTY. The first idea that occurs to me is something alike:
command > /dev/sometty
Unfortunately, the
command
is run before it is piped, and no tricks likeecho `command`
will work, no matter how many weird bash characters ($
,`
,"
, etc.) are there. So/dev/sometty
simply gets some text.The problem is that, sometimes, it is even worth for I to pipe those commands into a file, make it executable, etc., or shortly: making a script and running it from the appropriate terminal. But that is a lot of work. I've been thinking of making a script to make these files, for an instruction:
termpipe -e "command1\ncommand2\"command 1 argument\\n(s)\"" -t /dev/sometty
it would do something like:
- pipe the commands to, say,
/tmp/termpipe-20140208-153029-1.sh
- make the file executable
- run the file in the appropriate terminal
- delete the script when it is done executing
AFAIK, the problem is in 3.: this doesn't solve any problem, as I'd need another
termpipe
instance to run the first on the appropriate terminal. And one for that one. And another for that, ad infinitum. So this cannot work. Or can it?...The solution could be to use a named pipe per terminal, and when each starts, a script would tell the pipe to forward anything it receives to the terminal, and then to execute it (like a sort of daemon).
I think this might work but I don't know how to set up the initial script. How can I? How can I tell the FIFO to give piped commands for the respective terminal to run? I don't know much Bash, so I'd appreciate full explanations.
-
Stéphane Chazelas over 10 yearsUse
screen
ortmux
(which have keyboard based copy pasting). On Linux, you can also use gpm to do copy-pasting with the mouse. -
Ievgen Chuchukalo over 10 years@StephaneChazelas, thanks, I didn't know
tmux
could do that. But isn't there any way for what I suggested work? -
Ievgen Chuchukalo over 10 years@Stephane, I've been searching, andit turns out what I was thinking works! Now I just need a way for my script to start whenever a terminal starts. Maybe using
cron
... But that's another question... -
Gilles 'SO- stop being evil' over 10 yearsI have no idea what you're trying to do. What does “Unfortunately, the command is run before it is piped”? There isn't even a pipe here, there's a redirection, and it happens before the command starts. Please explain what you mean by piping, or better, use standard terminology.
-
Ievgen Chuchukalo over 10 years@Gilles, considering
command > /dev/sometty
to becommand | tee /dev/sometty
isn't that|
an unnamed pipe? Sorry if this is an innapropriate name, it's what I've always heard. -
Gilles 'SO- stop being evil' over 10 years@JMCF125
|
creates a pipe.>
doesn't. And even if I interpret “redirection” when you wrote “pipe”, I have no idea what you're asking:command >/dev/sometty
does redirect the output of the command to another terminal. -
Ievgen Chuchukalo over 10 years@Gilles, it redirects the output. I was looking for something to redirect as input, and then interpret it in the target. Compare my solution below,
echo "command" > tty3pipe
(after the scripting before), withcommand > /dev/tty3
. How can I make this clearer? (note: this is not a void question, it's real asking for improvement; if an expert doesn't understand my question, then there's something wrong with the way I wrote it) -
Gilles 'SO- stop being evil' over 10 yearsSo it's an interactive command? Can you give an example? Did you try
command </dev/tty3 >/dev/tty3 2>/dev/tty3
? (If this dialog gets any longer, please consider continuing in chat.) -
Ievgen Chuchukalo over 10 years@Gilles, I didn't, I remember people in Stack Overflow writing this to not be possible! (at least with usual
>
and<
) Thanks! But that does do the same as what I got below, only with colours by default, unlike my solution. Why is that? May you post an answer please? -
Ievgen Chuchukalo over 10 years@Gilles, ah, now I see... So that makes the command go to
/dev/tty3
for input, output, and error messages, right? I can put that as an answer, but I don't want to steal your idea. Maybe one could make a script to avoid writing/dev/tty3
thrice. In fact, consider it done. -
Gilles 'SO- stop being evil' over 10 yearsI still don't understand what you're asking. I stumbled in the dark and seem to have found something that satisfies you, but I don't know if it really answers the question (and in fact I suspect it won't work — as I said, if there's a shell or other program already running on
/dev/tty3
, and you run another program getting input from/dev/tty3
, they will compete for input). -
Ievgen Chuchukalo over 10 years@Gilles, I'm supposing nothing is being inputed/outputed in
/dev/tty3
. An example use would be: I find a long command in the internet that does what I want. I was already on the directory I am supposed to be to run the command in/dev/tty3
. But I can't copy it to there. Sure, I can dopwd > /dev/pts/0
, but I'll have to copy the directory name andcd
there before I copy the other command. Giving the command for/dev/tty3
to take care of is just easier. -
Gilles 'SO- stop being evil' over 10 years@JMCF125 If I understand your last comment correctly, then what I proposed doesn't do it. The command is executed in the current directory of the shell it was typed in. It seems you want the command to be executed by the shell that is running in another terminal, not just with its input and output connected to another terminal. Is that it? (You may want to read What is the exact difference between a 'terminal', a 'shell', a 'tty' and a 'console'?)
-
Ievgen Chuchukalo over 10 years@Gilles, damn it, I was in the same directory in both when testing! You're right, it doesn't work.
-
Ievgen Chuchukalo over 10 years@Gilles, thanks, but I already read that. Though I use "terminal" as a catch-all term for TTYs and pseudo-TTYs (terminal emulators). BTW, learning a bit about
sed
, I got my solution below automatized! Withoutcron
! I will post it ASAP.
- pipe the commands to, say,
-
Ievgen Chuchukalo over 10 yearsI will update this to run the script on start-up for every terminal ASAP.
-
Ievgen Chuchukalo over 10 yearsI see as @Gilles referred, if the target terminal is running something (with input, output and errors displayed there), there may be a problem. Say, with
startx
, there's simply no shown output of the directed command; but it can be much worse. I will try to address to that problem ASAP. -
Ievgen Chuchukalo over 10 years@ChrisDown, thanks, now I fixed it in my computer as well. I didn't notice the mistake (still a newbie in Bash), just forked it from here, where it is wrong originally.
-
bgStack15 almost 10 yearsThis works fantastically on the ksh .profile on AIX! This will be very handy in the future.