Attach to the output of a running process
Read the stdout/stderr of an already-running process you did not launch — for debugging daemons, observing what a frozen-looking job is doing, and tailing logs that weren't redirected at start.
How to attach to the output of a running process in each shell
sudo strace -p 12345 -s 1000 -e trace=write`-s 1000` = show up to 1000 bytes per call (default 32). `-e trace=write` filters to write syscalls only. Linux only. Requires CAP_SYS_PTRACE — sudo or `setcap cap_sys_ptrace=eip /usr/bin/strace`. Ubuntu disables ptrace by default; `echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope` enables.
sudo strace -p 12345 -s 1000 -e trace=writesudo strace -p 12345 -s 1000 -e trace=writeGet-CimInstance Win32_Process -Filter "ProcessId = 12345" | Select CommandLine, ExecutablePathWindows has NO equivalent to `strace -p` for normal user — needs ETW providers (`logman create trace …`) or DTrace-for-Windows. For pwsh's OWN background output: `Start-Transcript` before launching, then tail the transcript file.
powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'ProcessId = 12345' | Select CommandLine"cmd has no native introspection. Shell out to pwsh. Or use SysInternals Process Monitor (`procmon.exe`) — captures all file/registry/network events including stdout writes, GUI-based filtering.
Equivalents listed for Bash, Zsh, Fish, PowerShell, cmd.exe.
Gotchas & notes
- **The hard truth: this is the hardest task on this site** — attaching to output of a process you didn't launch is fundamentally restricted by OS security. On Linux, `strace -p PID -e write -s 9999` shows every `write()` syscall the process makes (which includes stdout/stderr) — but you only see new writes, not buffered backlog, and the format is `write(1, "actual text", 11) = 11` (you must parse out the quoted strings). It DOES NOT show stdout that was redirected to a file; for that, `tail -f /proc/PID/fd/1` (Linux only — `/proc/PID/fd/N` are symlinks to the open files, and 1 is stdout). If stdout went to a pipe, `/proc/PID/fd/1` symlinks to `pipe:[INODE]` and is not readable.
- **`reptyr` is the closest tool to "give me a real terminal for that running process"** (`apt install reptyr`). It detaches the process from its current terminal and reattaches to YOUR terminal — input + output both work. Requires the same ptrace privileges as strace. CAVEATS: programs with deep tty handling (vim, less, mosh) often break on reattach because they cached the original terminal's dimensions and capabilities; new SIGWINCH may not propagate cleanly. Best for daemons that just print to stdout (build scripts, long-running aggregators). Closest macOS / BSD equivalent: NONE (lack of /proc + SIP restrictions make this nearly impossible without disabling SIP).
- **macOS SIP prevents most introspection**: `dtruss` (DTrace) requires SIP off (`csrutil disable` from Recovery mode — DANGEROUS, off-by-default in modern macOS). `sample -file PID 10` is the SIP-friendly partial answer (samples stack traces for 10 seconds — useful for "what is this process doing right now" but doesn't capture stdout). `lldb -p PID` attaches a debugger; printing variables works but stdout is still the original tty. Practical advice on macOS: if you might need to inspect output later, redirect to a file at launch time (`./cmd 2>&1 | tee output.log` or `./cmd >> output.log 2>&1`); retrofitting introspection is hard.
- **Windows: ETW (Event Tracing for Windows) is the underlying primitive**: every process emits ETW events; `logman.exe` configures providers; `pwsh wpr.exe` (Windows Performance Recorder) captures. Sysinternals **Process Monitor** (`procmon.exe`) wraps this with GUI: filter on PID, watch every file/registry/network operation including stdout writes to console (CONOUT$). For a single console process showing live output, the SysInternals **DebugView** (`dbgview.exe`) captures OutputDebugString calls — useful for apps that use `OutputDebugString` for trace logging. Powershell jobs (`Start-Job` / `Start-ThreadJob`) maintain their own output buffer — `Receive-Job -Keep $job` streams output without removing it.
- **The right answer is usually "redirect at launch"**: every problem in this page exists because the process didn't redirect stdout/stderr to a known file when it started. Production daemons should: launch with `cmd >>/var/log/cmd.log 2>&1 &` or use systemd's `StandardOutput=file:/path/to/log`; one-off scripts run in `tmux` (output is in tmux's scrollback buffer, accessible via `tmux capture-pane -p`); pwsh jobs/scripts use `Start-Transcript` from the start. Retrofitting attach-to-output is a sign that something upstream went wrong — the next iteration of that script/daemon should pre-redirect. Fix the systemic issue, don't become an expert in strace tricks.
Related commands
Related tasks
- Tail a log file in real time— Follow a growing log file as new lines are appended (`tail -f`-style).
- Wait for a process to finish— Block until a given process exits — useful for sequencing, dependency-management scripts, and orchestrated shutdowns.
- Find a process ID by name— Look up the PID(s) of a running process given its executable name — the lookup that precedes most kill / signal / inspect operations.
- Run a command as a daemon— Detach a process from the controlling terminal and any parent shell — so it keeps running after logout, SSH disconnect, or terminal close.