9
ps -o pid,ppid,stat,exe -e | grep deleted

generates output like this:

   1777    1346 Sl   /usr/bin/python3.10 (deleted)
   1778    1346 Sl   /usr/bin/python3.10 (deleted)
   1825    1327 Ss   /usr/lib/bluetooth/obexd (deleted)
   2007       1 Sl   /usr/bin/python3.10 (deleted)
   2101    1346 S    /usr/bin/python3.10 (deleted)
   2199       1 Sl   /usr/bin/python3.10 (deleted)
 371565  371305 SLl  /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitNetworkProcess (deleted)
 371566  371305 SLl  /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitWebProcess (deleted)
 376426  371305 SLl  /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitWebProcess (deleted)
 380141  371305 SLl  /usr/lib/x86_64-linux-gnu/webkit2gtk-4.0/WebKitWebProcess (deleted)

What does the (deleted) mean & how can I get ps to list the path without appending it?

2 Answers 2

10

On Linux, ps gets that information by doing a readlink("/proc/<pid>/exe").

$ ls -l /proc/self/exe
lrwxrwxrwx 1 chazelas chazelas 0 Dec 17 10:35 /proc/self/exe -> /usr/bin/ls

That file is a magic symlink to the file that the given process (or any of its ancestor as not all processes execute files) last executed. If the file has been deleted (and potentially replaced by a new version like after a package update), a (deleted) is appended to the string returned by readlink(). That symlink can still be followed to the actual deleted file (and in that way it is magic).

$ cp /bin/sleep .
$ ./sleep 1h &
[1] 17417
$ ls -ld "/proc/$!/exe"
lrwxrwxrwx 1 chazelas chazelas 0 Dec 17 10:38 /proc/17417/exe -> /home/chazelas/sleep*
$ rm sleep
$ ls -ld "/proc/$!/exe"
lrwxrwxrwx 1 chazelas chazelas 0 Dec 17 10:38 /proc/17417/exe -> '/home/chazelas/sleep (deleted)'

New version of sleep:

$ cp /bin/sleep .
$ ps -o exe -p "$!"
EXE
/home/chazelas/sleep (deleted)
$ ls -ld "/proc/$!/exe"
lrwxrwxrwx 1 chazelas chazelas 0 Dec 17 10:38 /proc/17417/exe -> '/home/chazelas/sleep (deleted)'
$ ls -iLd "/proc/$!/exe" sleep
3114951 /proc/17417/exe*  3114969 sleep*

With -L ls follows the link (by using stat() instead of lstat()) and it is able to get the corresponding inode number.

We see that's two different files (different inode number).

$! is still running the old deleted version of sleep, that file has no path on the filesystem other than that /proc/$!/exe magic symlink¹.

/home/chazelas/sleep is now a different executable, so removing that (deleted) would be wrong as it would refer to the wrong file. Here, since exe is the last field, you can remove it by piping the output to:

sed 's/ (deleted)$//'
$ ps -o pid,ppid,stat,exe
    PID    PPID STAT EXE
  18928   11196 Ss   /usr/bin/zsh
  18943   18928 SN   /home/chazelas/sleep (deleted)
  18967   18928 R+   /usr/bin/ps
$ ps -o pid,ppid,stat,exe | sed 's/ (deleted)$//'
    PID    PPID STAT EXE
  18928   11196 Ss   /usr/bin/zsh
  18943   18928 SN   /home/chazelas/sleep
  18968   18928 R+   /usr/bin/ps
  18969   18928 S+   /usr/bin/sed

But again, that would be a lie as /home/chazelas/sleep is not the executable that process 18943 is running, it's another sleep command that is now nowhere to be found as it has been deleted since that process executed it.


¹ and corresponding /proc/<pid>/exe for other processes potentially executing it or /proc/<pid>/fd/<fd> for processes having that file opened on some fd, or potentially some hard links to it.

1
  • Could something like chroot confuse the output, by making readlink not find these paths inside the jail? Commented Dec 18, 2023 at 20:54
2

In your ps command, using the exe parameter you asked for printing the path of the executable.

man proc would tell more about that field :

If the pathname has been unlinked, the symbolic link will contain the string '(deleted)' appended to the original pathname.

Since this is not an option (when requesting the path to be displayed) and you absolutely need the path to be displayed then the only solution I can think of is to post process the result. For example using sed :

ps -o pid,ppid,stat,exe -e | sed "s/(deleted)//g"

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.