How to Redirect stdin/stdout to a Background Process in Linux


1 views

When you run a process in the background using & in Linux, you effectively lose direct access to its standard input (stdin). This becomes problematic when you need to interact with a long-running server process that only accepts control commands through stdin.

Normally, you'd use:

./myserver < input.txt > output.txt &

But what if you forgot to set this up initially? The process is already running, and you need to establish communication channels after the fact.

One effective method is using gdb to attach to the running process and modify its file descriptors:

# Create a named pipe
mkfifo /tmp/myserver_input

# Attach gdb to the running process (replace PID)
gdb -p PID <<EOF
call close(0)
call open("/tmp/myserver_input", 0)
detach
quit
EOF

The reptyr tool can move a process to a new terminal:

sudo apt-get install reptyr
reptyr PID

This allows you to interact with the process in your current terminal session.

For long-term solutions, consider these approaches:

# Method 1: Using screen/tmux
screen -dmS myserver ./myserver
screen -r myserver

# Method 2: Using socat
socat EXEC:./myserver PTY,link=/tmp/myserver

To avoid this situation in the future:

# Use nohup with redirection
nohup ./myserver < input.txt > output.txt 2>&1 &

# Or use tmux/screen
tmux new -d -s myserver './myserver'

You started a server process in the background (myserver &) on your Ubuntu system, and now you need to send commands to its stdin. Maybe it's an interactive server that accepts control commands, or perhaps you need to debug it by feeding test input. But how do you access stdin after the process is already running?

Normally, you'd use pipes or redirection when starting the process:

# The proper way if you planned ahead
mkfifo /tmp/server_input
myserver < /tmp/server_input &

But when the process is already running, these methods won't help:

  • Simple redirection (> /proc/PID/fd/0) doesn't work because stdin is read-only
  • Attaching with gdb is complex and might crash your process
  • screen or tmux would have needed to be set up beforehand

1. Using reptyr to Attach to Existing Process

First install reptyr:

sudo apt-get install reptyr

Then:

# Start a new screen session
screen

# In another terminal, attach your process to screen
reptyr $(pgrep myserver)

Now you can interact with your process through screen's terminal.

2. The GDB Injection Method

This is more advanced but works when reptyr doesn't:

# Attach gdb to your process
gdb -p $(pgrep myserver)

# In gdb:
(gdb) call close(0)
(gdb) call open("/tmp/new_stdin", 0600)
(gdb) continue
(gdb) quit

Now create /tmp/new_stdin as a named pipe:

mkfifo /tmp/new_stdin

You can now write to this pipe and the process will receive it as stdin.

3. The socat Bridge Solution

Create a communication bridge:

# First find your process's terminal
ls -l /proc/$(pgrep myserver)/fd/0

# Then create a bridge
socat - UNIX-CONNECT:/dev/pts/X  # Replace X with your terminal number

For future reference, here are better ways to start interactive background processes:

# Using screen
screen -dmS myserver ./myserver

# Using tmux
tmux new -d -s myserver './myserver'

# Using named pipes
mkfifo server_in
tail -f server_in | ./myserver &

If you're having trouble:

  • Check process status: ps aux | grep myserver
  • Verify file descriptors: ls -l /proc/PID/fd/
  • Test with a simple process first before trying on your production server