Execute a command in another terminal via /dev/pts
I completely get what you are asking. You can achieve this by writing and executing a small piece of code in C yourself. This should give you some idea.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <string.h>
#include <unistd.h>
void print_help(char *prog_name) {
printf("Usage: %s [-n] DEVNAME COMMAND\n", prog_name);
printf("Usage: '-n' is an optional argument if you want to push a new line at the end of the text\n");
printf("Usage: Will require 'sudo' to run if the executable is not setuid root\n");
exit(1);
}
int main (int argc, char *argv[]) {
char *cmd, *nl = "\n";
int i, fd;
int devno, commandno, newline;
int mem_len;
devno = 1; commandno = 2; newline = 0;
if (argc < 3) {
print_help(argv[0]);
}
if (argc > 3 && argv[1][0] == '-' && argv[1][1] == 'n') {
devno = 2; commandno = 3; newline=1;
} else if (argc > 3 && argv[1][0] == '-' && argv[1][1] != 'n') {
printf("Invalid Option\n");
print_help(argv[0]);
}
fd = open(argv[devno],O_RDWR);
if(fd == -1) {
perror("open DEVICE");
exit(1);
}
mem_len = 0;
for (i = commandno; i < argc; i++) {
mem_len += strlen(argv[i]) + 2;
if (i > commandno) {
cmd = (char *)realloc((void *)cmd, mem_len);
} else { // i == commandno
cmd = (char *)malloc(mem_len);
}
strcat(cmd, argv[i]);
strcat(cmd, " ");
}
if (newline == 0)
usleep(225000);
for (i = 0; cmd[i]; i++)
ioctl (fd, TIOCSTI, cmd+i);
if (newline == 1)
ioctl (fd, TIOCSTI, nl);
close(fd);
free((void *)cmd);
exit (0);
}
Compile and execute it with sudo
permissions. For example, if you want to execute a command on /dev/pts/3
, then simply do a sudo ./a.out -n /dev/pts/3 whoami
, runs a whoami
on /dev/pts/3
.
This code was completely taken from this page.
Executing string sent from one terminal in another in Linux pseudo-terminal
No; terminals don't execute commands. They're just channels for data.
You can sort of run a command and attach it to another terminal like this, though:
ls </dev/pts/2 >/dev/pts/2 2>/dev/pts/2
It won't behave exactly like you ran it from that terminal, though, as it won't have that device set as its controlling terminal. It's reasonably close, though.
why can't I write to the standard input of my terminal device from another terminal
You can do it by doing this commands, (from /dev/pts/1 or another tty):
exec 1>/dev/pts/0
to deactivate
exec 1>/dev/pts/1 #or your actually original tty address.
Basically you are supplanting the tty stdin.
Edited for more details.
"exec" in this case starts a new bash and you can feed this with a new set of environment variables that normally you can not change on the fly. For more details please do "man exec".
"1>/dev/pts/0" here we are saying, "whatever I type on this new bash, write it to this another one, and indeed it will do it, but all the stdout will be displayed at the original tty.
Good luck learning linux, I hope you enjoy it.
Open terminal, run command, return to SAME terminal later and execute another command
In order to write commands to a terminal from another program or terminal you must use a system input-output control system call (ioctl). (This may not always be the case but is is the solution I have found). I will also be presenting a solution in Python but I have cited other resources including a method in c below.
First, you need the process identifier (PID) of the terminal instance you wish to send commands to for it to execute. This can be determined in a few ways but the easiest way I found was via the following command:
ps -A | grep bash --color=always
This will output a list of open terminals and their PIDs and pts numbers. The easiest way I find to know which is the one you want is to open a terminal via your program, run the aforementioned command and the recently opened terminal will be the last on the list. I'm sure you can get more fancy with it if you need to be certain but that isn't the point of this question. You will see something like this, where the pts/# is what you're after
108514 pts/2 00:00:00 bash
Next use the following code and simply save it to a .py file of your choice, (credit for this code goes to the answer in the first link below, the Python one). Note that the example below is hard coded to send the "ls" command. Again, either change the hard coded command or make it not hard coded depending on your own preference and use case.
import fcntl
import sys
import termios
with open(sys.argv[1], 'w') as fd:
for c in "ls\n":
fcntl.ioctl(fd, termios.TIOCSTI, c)
Then, simply call the new function and pass it the following path based on the pts number found previously like so:
python <your_fcn_name_here).py /dev/pts/#
Worked fine for me on Ubuntu 14.04. I'll be trying it on CentOS soon. Didn't have to install any python libraries to do it.
Other Resources
This question has been posed differently here:
- In Python: https://stackoverflow.com/a/29615101/7590133
- In C: https://stackoverflow.com/a/7370822/7590133
For more good information regarding IOCTLs:
- IOCTL Linux device driver
How can I start a bash on a specific /dev/ttyX (or /dev/pts/X) device?
fork()
a child process. Open the serial device or pseudotty and dup2()
it to fd's 0, 1 and 2. execv()
your preferred shell.
Race condition when reading from /dev/pts/x
Actually, bash
sets the terminal in non canonical mode when reading from the terminal and when it gets an end of line, it sets back the terminal in canonical mode to run the command line.
The same experience can be done with two terminals:
- Terminal#1 (/dev/pts/6): launch
strace /bin/bash
- Terminal#2: launch
strace cat /dev/pts/6
The bash shell on terminal#1 deactivates the canonical mode and calls pselect() to wait for the input:
$ strace /bin/bash
[...]
ioctl(0, TCGETS, {B38400 opost isig -icanon -echo ...}) = 0
[...]
pselect6(1, [0], NULL, NULL, NULL, {[], 8}
On terminal#2, the cat
command merely calls a blocking read() to get chars from the terminal:
$ strace cat /dev/pts/6
[...]
openat(AT_FDCWD, "/dev/pts/6", O_RDONLY) = 3
[...]
read(3,
So, both bash
and cat
are reading concurrently on the terminal. When we type characters in terminal#1, pselect() returns to indicate that a character is available and then bash
calls a blocking read() to get the char. But the concurrent read() from cat
stills the characters between the calls to pselect() and read() by bash
. Sometimes, bash
is able to get a character before cat
.
Here is an example where pselect() returns because a character is available (I typed "Y") and a following read() is called to get it on terminal#1:
pselect6(1, [0], NULL, NULL, NULL, {[], 8}) = 1 (in [0])
read(0,
But read() from cat
on the other terminal succeeded to get the character before the read() of bash
:
write(1, "Y", 1Y) = 1
read(3,
Sometimes, bash
is able to get the typed character before cat
. Generally, when it is blocked on its read() call (that is to say it missed the character detected by pselect() but it will be able to get one of the subsequent typed characters before one of the calls to read() by cat
)...
Side note
When we launch stty -a
under bash, the display shows that the terminal is in canonical mode:
$ stty -a
[...]
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke -flusho -extproc
This is because of the fact that bash
reactivates the canonical mode before launching the stty
command.
Related Topics
"Must Be Connected to a Terminal Error" with Screen -X Command on a Linux Container
Shared Volume in Docker Through Vagrant
Executing Exe or Bat File on Remote Windows Machine from *Nix
Sudo Apt-Get Update Fail on Ubuntu 17.04
How to Find Out What Program's on The Other End of a Local Socket
Sed Regex Problem on Mac, Works Fine on Linux
Set Docker Image Username at Container Creation Time
Linux Asynch Io - Difference Between Aio.H and Libaio.H
Bash: Split Stdout from Multiple Concurrent Commands into Columns
Qemu on Raspberry Pi Arch Linux Latest Sd Image
Linux Append Console Output to a Logfile
How to Sleep 10 Seconds Before Running a Linux Command
How to Generate a Static HTML File from a Swagger Documentation
How to Accept Multiple Tcp Connections in Perl
Gdb Complains No Source Available
How Are Posix Threads Implemented on Linux