Reputation: 635
I have a pair of linux C programs that use pseudo terminals /dev/pts/*
to communicate to each other. The pty on which can communicate is passed as command line argument to these programs.
I can create a pair of pty devices using socat as follows:
socat -d -d pty,raw,echo=0 pty,raw,echo=0
The output of above gives as:
2018/07/05 17:56:54 socat[58319] N PTY is /dev/pts/1
2018/07/05 17:56:54 socat[58319] N PTY is /dev/pts/3
2018/07/05 17:56:54 socat[58319] N starting data transfer loop with FDs [7,7] and [9,9]
how can I extract the pty nodes, /dev/pts/*
from socat
's output and pass to my application via command line in a shell script:
$./test_pty_app /dev/pts/1 &
$./test_pty_app /dev/pts/2 &
I saw a similar question that can do this in python here Thanks!
Upvotes: 3
Views: 1395
Reputation: 3660
socat offers a nice feature that is exactly what you need: the "link" parameter. Instead of guessing which PTS socat assigned, you just have it make a symbolic link with a specific name.
Specifically, instead of:
socat -d -d pty,raw,echo=0 pty,raw,echo=0
You indicate the names of the symlinks that socat should create:
socat -d -d pty,raw,echo=0,link=/tmp/pts0 pty,raw,echo=0,link=/tmp/pts1
socat's log output will not change at all:
2025/01/01 20:56:21 socat[563916] N PTY is /dev/pts/1
2025/01/01 20:56:21 socat[563916] N PTY is /dev/pts/3
2025/01/01 20:56:21 socat[563916] N starting data transfer loop with FDs [5,5] and [7,7]
But if you ls -l /tmp/pts*
:
$ ls -l /tmp/pts*
lrwxrwxrwx 1 raul raul 10 ene 1 20:56 /tmp/pts0 -> /dev/pts/1
lrwxrwxrwx 1 raul raul 10 ene 1 20:56 /tmp/pts1 -> /dev/pts/3
So that your applications will use /tmp/pts0
and /tmp/pts1
(or however you want to call them - you could and probably should assign better names to indicate their role).
In the documentation:
CWlink= Generates a symbolic link that points to the actual pseudo terminal (pty). This might help to solve the problem that ptys are generated with more or less unpredictable names, making it difficult to directly access the socat generated pty automatically. With this option, the user can specify a dqfixdq point in the file hierarchy that helps him to access the actual pty (example). Beginning with socat version 1.4.3, the symbolic link is removed when the address is closed (but see option unlink-close).
Upvotes: 0
Reputation: 207748
Updated Answer
It looks like you'll have to use a file if socat
must be backgrounded.
( socat ... 2>&1 | grep -Eo "/dev/pts/\d+" > /tmp/a ) &
portA=$(head -n 1 /tmp/a)
portB=$(tail -n 1 /tmp/a)
Original Answer
@jeremysprofile 's answer is probably more sensible but, just for fun, you could do either of these also:
socat ... | grep -Eo "/dev/pts/\d+" | { read portA; read portB; }
Or, using bash's "process substitution", you could do:
{ read portA; read portB; } < <(socat ... | grep -Eo "/dev/pts/\d+")
Then you would do this after either of them:
./test_pty_app $portA &
./test_pty_app $portB &
Upvotes: 2
Reputation: 11465
arr=($(socat -d -d pty,raw,echo=0 pty,raw,echo=0 2>&1 | grep -oh "/dev/pts/\w*"))
now "${arr[0]}"
and "${arr[1]}"
are your two tty ports.
grep -oh
prints out only the pattern it matches, nothing else. `/dev/pts/\w* matches only something starting with /dev/pts/ and then any number of alphanumeric (or _) characters, which basically means "until the end of the word".
Upvotes: 2