4

Let's say I have a process that is echoing the user input, running in a shell. Then how can you pass data to/from that shell from another terminal? Is it possible without using an intermediate file?

E.g., if I have the code

fgets(string, LEN, stdin);
printf("%s", string);

Then, is it possible to pass data to stdin, and to get data from stdout via a different shell ?

drC1Ron
  • 161
  • 1
    For testing, you can replace your program with the "cat" command without parameters. Now, your question is a bit fuzzy for me. Can you elaborate with an example? Try giving the goal rather than only the method, in case the method to achieve the goal isn't what you'd think. – A.B Dec 21 '18 at 12:44
  • Hi A.B. I want to give command-line arguments to a process running in a shell, from a second terminal. The process is not written by me, and I know only how to start it and how to execute commands. I would like to execute commands from a remote user (via TCP), and as a first step of achieving this, I'm trying to pass commands from a second terminal running locally. – drC1Ron Dec 21 '18 at 12:58
  • edit: … I'm trying to pass commands from a second terminal running locally, and without editing the first process. If I'm able to pass data to the "stdin" of the first process, from the second process (second shell) then I think I'm able to achieve this – drC1Ron Dec 21 '18 at 13:11

2 Answers2

9

I'm not exactly sure if I got what you mean, but.

Within a single shell session (terminal), you'd use a pipeline to pass data from one command to another, like so:

$ ls -l | grep something

If you need to do that between two different shells, you can use a named pipe:

tty1$ mkfifo /tmp/mypipe
tty1$ ls -l > /tmp/mypipe
tty2$ grep something < /tmp/mypipe

It would be safer to use mktemp to create a directory to place the named pipe in:

tty1$ dir=$(mktemp -d)
tty1$ mkfifo "$dir/mypipe"
tty1$ ls -l > "$dir/mypipe"
tty1$ rm -r "$dir"

though that requires copying the path to the other window, possibly by hand.

Of course, a named pipe acts a bit like an intermediate file, in that it needs a path name. But it acts more like a pipe in that the data doesn't get written to permanent storage, and the reader waits for the writer if the writer is slow, instead of possibly encountering a premature end-of-file.

(You'd usually use ls -l *something* instead of ls | grep, but it works as an example.)

ilkkachu
  • 138,973
  • I guess you have answered the question according to the somewhat inaccurate title. Sorry 'bout that. Your answer is helpful, but not quite what I need. – drC1Ron Dec 21 '18 at 13:19
  • If I write the following in a terminal 'echo "something" > /proc//fd/0' then it seems as if I write "something" to the "standard-input" of the process identified by PID. – drC1Ron Dec 21 '18 at 14:01
  • Alternatively, from user "John" in his question "is it possible to send data to the shell of another pseudo-terminal", you can write 'echo "something" > /dev/pts/', where /pts/nr is the relevant shell id. – drC1Ron Dec 21 '18 at 14:15
  • Btw, the '/proc//fd/0' is from Ilya Marchenko, answering Johns question. – drC1Ron Dec 21 '18 at 14:16
  • I thought that 'echo "command" > /proc//fd/0' solved my issue, but the "command" is only echoed in the main shell. The associated process does not read the command. – drC1Ron Dec 21 '18 at 14:25
  • 2
    @RonnyLandsverk, no, writing to /proc/$pid/fd/0 writes to where ever fd 0 of that process is connected. It does not write to the process, but rather the write goes to the same place as writes to fd 0 from the process go. (Except that opening /proc/$pid/fd/0 creates a new file description, with a separate seek location etc.) – ilkkachu Dec 21 '18 at 14:45
  • 1
    RonnyLandsverk, please refine your question and its title as you learn more about it by clicking [edit] and expanding on it, and/or make the question more clear to those of us trying to help. Comments, pretty much, are when we need to know more; your question should contain everything relevant about your needs by the time the issue is resolved. – K7AAY Dec 21 '18 at 17:03
2

I think @ilkkachu's answer is helpful, and provides what you need. I will try to explain with some details, and at the same time I learn how to use a fifo.

  • Prepare two command line windows, w1 and w2 in the same computer

  • Create the listening program, I made a shellscript in w1

    #!/bin/bash
    
    while true
    do
     read string
     if [ "${string:0:4}" == "Stop" ]
     then
      printf "Gotcha\n"
      break
     elif [ "$string" != "" ]
     then
      printf "$string "
     else
      sleep 3
     fi
    done
    
  • Prepare the fifo in w1

    dir=$(mktemp -d)
    mkfifo "$dir/mypipe"
    
  • Start the program and let it wait for input from to the fifo in w1

    < "$dir/mypipe" ./program
    
  • Look for the fifo and echo some strings to it in w2

    $ find /tmp -name mypipe 2>/dev/null
    /tmp/tmp.dRhpqajJqz/mypipe
    
    $ > '/tmp/tmp.dRhpqajJqz/mypipe' echo qwerty
    $ > '/tmp/tmp.dRhpqajJqz/mypipe' echo asdf
    $ > '/tmp/tmp.dRhpqajJqz/mypipe' echo Stopp
    
  • Look at the output in w1

    qwerty asdf Gotcha
    $ 
    

You can also make this more automatic, for example like the following, which assumes that there is only one temporary file with the name mypipe,

  • start the program again in w1

    < "$dir/mypipe" ./program
    
  • in w2

    > $(find /tmp -name mypipe 2>/dev/null) echo 'Hello World'
    > $(find /tmp -name mypipe 2>/dev/null) echo 'Stop the World'
    
  • Look at the output in w1

    Hello World Gotcha
    $
    

Demo C program,

#include <stdio.h>
#include <string.h>

int main () {

 char string[21];
 while(1){
    fgets(string, 20, stdin);
    string[strlen(string)-1] = 0;
    if(strcmp("Stop", string) == 0){
        printf("Gotcha");
        return 1;
    }
 }
}

This C program writes only, when it has read 'Stop'.

sudodus
  • 6,421
  • @sudosus - this is very helpful. It works and I'll try to figure out the details on my own, but are you willing to elaborate on a couple of points if I'm not succesfull ? – drC1Ron Dec 21 '18 at 17:40
  • @RonnyLandsverk, Good luck :-) If you need more help, please ask in comments here, and I will try to explain. – sudodus Dec 21 '18 at 18:16
  • @sudosus Your answer works perfect for shell-script. When I try the same with a c-program, waiting for - and echoing user input, then in general, nothing is written to the stdout. When the user-input matches the "Stop" string, and hence the program returns, then the "Stop" string is echoed, and the "Gotcha" message is displayed. Are the echoed strings before that written to the fifo buffer without being displayed ? – drC1Ron Dec 23 '18 at 12:49
  • @RonnyLandsverk, Yes. I edited the answer to add a demo C program, that I made to test that it works with the read and write methods that you use in your question. This C program writes only, when it has read 'Stop'. – sudodus Dec 23 '18 at 13:12
  • @RonnyLandsverk, But you can make your C program write something at all inputs, for example by adding a printf line without any condition if ... – sudodus Dec 23 '18 at 13:21