3

Is it correct that the output of jobs contains the working directory when invoking each job (not necessarily the current working directory of each job)?

$ jobs -l | grep JDBC
[15]  20422 Running   PDFXCview all.pdf &  (wd: ~/mydata/dirlinks/cs/SQL/API/JDBC/general/official/tutorials)
[20]  20542 Running   PDFXCview all.pdf &  (wd: ~/mydata/dirlinks/cs/SQL/API/JDBC/general/wikipedia)

Similarly, in ps, is it possible to get the previous working directory of each process when invoking it

In pgrep, is it possible to search in the pathname (string) of the previous working directory of each process when invoking it, like pgrep ... <pattern_in_working_dir_pathname>?

I would like to search for processes, by keywords in their working directories when invoking them

Thanks.

Tim
  • 101,790
  • Jobs shows the directory that a jobs was started in. Not its current working directory. try (cd ~/Downloads; sleep 100) & cd /; jobs – ctrl-alt-delor Jul 28 '18 at 16:46

3 Answers3

3

The jobs command may show working directory the program started in, if that directory is different to the shell's current one. That's because the shell is tracking what it knows (where the process started), not the current state.

It's also dependent on the shell.

eg with bash

bash-4.4$ cd /tmp
bash-4.4$ sleep 1000 &
[1] 24807
bash-4.4$ jobs -l
[1]+ 24807 Running                 sleep 1000 &
bash-4.4$ cd /
bash-4.4$ jobs -l
[1]+ 24807 Running                 sleep 1000 &  (wd: /tmp)

But ksh93 doesn't do that

$ sleep 1000 &
[1]     7164
$ jobs -l
[1] + 7164       Running                 sleep 1000 &
$ cd /
$ jobs -l
[1] + 7164       Running                 sleep 1000 &
$ 

I don't believe there's any portable way of finding the cwd of a process. fstat, pwdx and similar may help. You may need root privileges to look at processes you don't own.

On Linux, the processes matching a specific path may be used by looking at the /proc/.../cwd symlink:

eg to find processes with /tmp in the path:

% sudo ls -l /proc/*/cwd | grep /tmp
lrwxrwxrwx. 1 sweh     sweh     0 Jul 28 09:38 /proc/23435/cwd -> /news/tmp
lrwxrwxrwx. 1 sweh     sweh     0 Jul 28 09:39 /proc/7124/cwd -> /news/tmp

Remember this may not match the process's internal representation of the directory because of symlinks:

$ cd /usr/tmp
$ pwd
/usr/tmp
$ ls -l /proc/self/cwd
lrwxrwxrwx. 1 sweh sweh 0 Jul 28 09:41 /proc/self/cwd -> /var/tmp/
$ ls -l /usr/tmp
lrwxrwxrwx 1 root root 10 May 13 09:39 /usr/tmp -> ../var/tmp/
$ 

Here the shell thinks I'm in /usr/tmp but really it's /var/tmp.

EDIT TO ADD:

There is a special case of this problem, where the question might be "what processes are using a mount point". This isn't reporting the cwd but any files that may be open.

So, for example:

$ sudo fuser -u -c /brick
/brick:               3552(root)
$ ps -p 3552
  PID TTY          TIME CMD
 3552 ?        00:04:51 glusterfsd
$

We know the glusterfsd process is the only one using the /brick filesystem

  • Thanks. What does the mount point used by a process mean? What is the different of a mount point and working directory of a process? – Tim Jul 29 '18 at 18:53
  • If you have /home as a mounted filesystem then something using /home/mylogin/foo/bar will be using the /home mountpoint. This could be cwd or an open file. – Stephen Harris Jul 30 '18 at 01:07
2

There isn't a portable way to do this with ps but you can use a for loop with ps to print all of the processes and then pipe it to another command to print their current working directories.

Let's start with pwdx which specifically prints the current working directory of a process.

Running as root:

for i in $(ps aux | awk '{print $2}'); do pwdx $i; done

ps aux | awk '{print $2}' prints the pid for each process.

pwdx $i Passes the i variable which is the pid's to pwdx

You can use pwdx on a pid itself but the for loop does them all together.

You can also use lsof but you may need to install the lsof package first depending on your system. Running as root:

for i in $(ps aux | awk '{print $2}'); do lsof -p $i | grep cwd; done

ps aux | awk '{print $2}' prints the PID for each process.

lsof -p $i Passes the i variable to lsof

grep cwd Prints the lines containing cwd or the current working directory.

In regards to the pgrep command, you can use it in the form of:

pgrep <process-name>

in order too find the pid of a process but you'll still have to pass it to either lsof or pwdx to find the current working directory.

The first for loop works with Fedora 28, Centos 7.5, RHEL 7.5, and Debian 9 but not FreeBSD 11.

The second for loop works with Fedora 28, Centos 7.5, RHEL 7.5, and Debian 9. It also works with FreeBSD 11.1 although in my case, it prints out warning messages regarding the lsof version being for FreeBSD 11 while mine is FreeBSD 11.1

Nasir Riley
  • 11,422
  • 1
    What Unix are you running ps aux on? On OpenBSD and Ubuntu, ps aux does not show working directory. – Kusalananda Jul 28 '18 at 07:09
  • @Kusalananda I was out last night when I posted my answer and wasn't able to test it. As a result, it seems that I forgot and I left off a part of it the command smacks head. Adding ww will make the columns wider and show as many columns as possible and adding f shows the hierarchy of the process. The questionner didn't specify which Unix/distro he's using and while I can't test it with every single one, I have confirmed that ps auxww works with CentOS 7.5, RHEL 7.5, Debian 9, and FreeBSD 11 although ps auxf doesn't show the hierarchy in FreeBSD 11. – Nasir Riley Jul 28 '18 at 13:08
  • @NasirRiley - ps auxww does not show the cwd on CentOS 7.5. ww stops ps from truncating output, which is useful for long process arguments, or when used with e (show environment) but doesn't otherwise add data. Compare ps auxe with ps auxwwe. But even that doesn't show current directory. eg $ ps auxwwe | grep httpd | tail -1 apache 29709 0.0 0.1 414980 7676 ? S Jul22 0:00 /usr/sbin/httpd -DFOREGROUND - there's no directory listed for that apache process. – Stephen Harris Jul 28 '18 at 13:48
  • @StephenHarris You are correct. I thought that by working directory that he meant where the command was running from. There isn't a portable way to do it with ps on its own so I've updated my answer. – Nasir Riley Jul 28 '18 at 16:36
  • lsof -d cwd seems to do the trick – Winny Mar 03 '21 at 15:35
2

The working directories of processes are knowable by other processes in many operating systems. They are queryable from the kernel in the BSDs and on Linux, using sysctl() and procfs respectively. However, neither the Linux ps command from procps nor the ps commands in the BSDs obtain and report this information.

To obtain the current directory of a process on the BSDs, the command is fstat, which reports the filesystem and i-node number.

% fstat -p $$|awk '{ if ("wd" == $4 || 1 == NR) print; }'
USER     CMD          PID   FD MOUNT      INUM MODE         SZ|DV R/W
JdeBP    zsh        71512   wd /usr/home/JdeBP      4 drwxr-xr-x     127  r
% 

Note that, of course, working directories can be reached by multiple names and those names can vary as things are renamed and links are created/destroyed. The stable part of them is the file object, the vnode, not the directory entries for reaching it.

So the Linux mechanism, that reports one name in /proc/pid/cwd, is not necessarily reliable.

Finally: note that the current directory of a process is not necessarily the working directory that it had when the process was spawned, which is all that job control shells actually know.

Further reading

JdeBP
  • 68,745