When debugging or monitoring Linux processes, developers often need to inspect which files a process has open. The traditional method using ls -l /proc/PID/fd
provides a static snapshot, but lacks the dynamic observation capabilities that modern debugging scenarios demand.
For real-time monitoring, we can combine the ls
approach with the watch
command:
watch -n 2 "ls -l /proc/1234/fd"
This refreshes every 2 seconds (adjustable with -n
), showing changes in the file descriptor table.
For more detailed information, lsof
offers superior capabilities:
watch -n 1 "lsof -p 1234"
This displays not just file descriptors but also socket connections, pipes, and other I/O channels.
For persistent monitoring with logging capabilities:
#!/bin/bash
PID=$1
INTERVAL=${2:-1}
LOG_FILE="fd_monitor_${PID}.log"
while true; do
echo "=== $(date) ===" >> $LOG_FILE
lsof -p $PID >> $LOG_FILE
sleep $INTERVAL
done
Usage: ./monitor_fd.sh 1234 0.5
(monitors PID 1234 every 0.5 seconds)
For kernel-level monitoring, consider using inotifywait
:
inotifywait -m /proc/1234/fd -e create,delete |
while read -r directory event file; do
echo "File descriptor $file was $event at $(date)"
done
Combine with grep
for focused monitoring:
watch -n 0.5 "lsof -p 1234 | grep -E 'REG|CHR'"
This filters for regular files and character devices only.
When debugging processes or analyzing system behavior, developers often need to monitor which files a process has opened. While ls -l /proc/PID/fd
provides this information, it's a static snapshot that requires manual repetition.
The most straightforward approach is using the watch
command combined with our original query:
watch -n 1 "ls -l /proc/PID/fd"
This refreshes the output every second (-n 1). Adjust the interval as needed.
For more detailed real-time monitoring, lsof
(LiSt Open Files) offers powerful options:
watch -n 1 "lsof -p PID"
This shows not just file descriptors but also sockets, pipes, and other file types.
For persistent monitoring with timestamps:
#!/bin/bash
PID=$1
INTERVAL=${2:-1} # Default to 1 second
while true; do
clear
echo "=== $(date) ==="
ls -l /proc/$PID/fd
sleep $INTERVAL
done
Save as fdmonitor.sh
, make executable (chmod +x fdmonitor.sh
), and run with ./fdmonitor.sh PID [interval]
.
For event-driven monitoring (rather than polling), consider inotifywait
:
inotifywait -m /proc/PID/fd
This triggers only when file descriptors change, but has limitations with /proc virtual filesystem.
For programmatic access:
import os
import time
def monitor_fds(pid, interval=1):
fd_path = f"/proc/{pid}/fd"
while True:
print(f"\n=== {time.ctime()} ===")
for fd in os.listdir(fd_path):
try:
link = os.readlink(f"{fd_path}/{fd}")
print(f"FD {fd} -> {link}")
except (FileNotFoundError, PermissionError):
continue
time.sleep(interval)
monitor_fds(1234) # Replace with target PID