Linux has a /proc directory and file‑system, which as far as I can tell, is not part of POSIX. In each /proc/$PID subdirectories, is a symbolic link, cwd, pointing to the actual working directory of the process of this PID (the cwd link is always up to date).

This symbolic link is convenient for some use case, like working with distinct shells and exchanging files between the two shells (formally, their working directories).

Is there a simple way to get something similar, only using POSIX feature?

More on the question

After a comment, more precision: it does not have to necessarily be a link and an environment variable lile $<PID>_CWD, would be as much fine too, although at first sigh, I don't believe such a solution exist. It just has to be easy to refer to (ex. symbolic link or environment variable) and be always up to date each time the other process switch it's working directory.

The solution does not need to necessarily be POSIX, and the most important aspect is portability, but POSIX is surely a guarantee.

  • 1
    Are you wanting POSIX, or portable? Things can be portable without being defined in POSIX. – Patrick Jul 8 '14 at 13:50
  • 1
    I don't think POSIX would concern itself with this fine of a detail and narrow of a use case. Solaris and AIX both have a pwdx command, so you may just create an alias or function called pwdx on Linux that wraps around readlink if you're looking for something portable. – Bratchley Jul 8 '14 at 14:07
  • 1
    Actually, on my RHEL5 system there is a pwdx command that comes with procps so that may be your answer. – Bratchley Jul 8 '14 at 14:10
  • 1
    @JoelDavis Actually, almost every Linux and Solaris has pwdx. But FreeBSD doesn't. – enedil Jul 8 '14 at 14:18
  • 2
    Fun fact: getcwd(3) used to work by calling stat(".") and readdir(".."), finding a matching inode number, and repeating the process upward until it hit the root directory. Good luck doing that in the context of another process. (I suppose one could use ptrace to inject a call to getcwd...) – zwol Jul 8 '14 at 20:22

I have a solution that uses lsof. It is not installed on BSD by default so if anyone want to use it on BSD, it is required to install it.

Make a shell script:

lsof -p $1 | grep cwd | awk '{print $9}'

Copy it to a directory in your path. It prints the working directory of PID given in the first argument, I.E.

$ script 1987
| improve this answer | |
  • 3
    By the way, this little variation too: lsof -p $PID | awk '/cwd/{print $9}'. – Hibou57 Jul 8 '14 at 15:38
  • @Hibou57 ok, I'm not an AWK expert. – enedil Jul 8 '14 at 15:39
  • 1
    +1, I did not want you to stay on 888 :p – Ramesh Jul 8 '14 at 16:24
  • 2
    You can save a little on lsof overhead with just lsof -d cwd -a -p $1 – mr.spuratic Jul 8 '14 at 17:25

POSIX doesn't offer much in terms of getting information about unrelated processes. There's only ps, really, and it doesn't give any information about the current directory. The C-level APIs aren't any better (in fact most of the information retrieved by ps can only be retrieved by parsing its output¹).

Funnily enough POSIX does offer a portable way to go the other way round: given a file, you can find out which processes have it open by calling fuser. The following snippet lists the PIDs of the processes that have a particular working directory:

fuser -f "$directory_name" 2>&1 | sed -e '$!d' -e 's/.*://' -e 's/  */\
/' | sed -n 's/c$//p'

If you want information about processes in a way that's portable in practice, use lsof. The author of lsof has done the work of implementing all the different ways of retrieving information on different unix variants.

For casual browsing:

lsof -a -p "$pid" -d cwd

For automated parsing:

lsof -a -p "$pid" -d cwd -F n | sed -e '1d' -e '2s/^n//'

Note that lsof replaces newlines by the string \n.

Some Unix variants offer methods that don't require third-party software, but these methods will be perforce specific to each variant. On a very related note, see Portability of file descriptor links

¹ Some old unices has ps setuid root and reading kernel memory, so using that setuid binary was the only way to obtain this information.

| improve this answer | |
  • I am not sure about the "it doesn't give any information about the current directory" : in most unixes, you can use ps in 2 ways: ps -options [= unix options, with a dash], or ps options [=BSD style options, without a dash]. Each comes with their own set of options (-X and X are probably not the same option). Using BSD options, one can: ps auexwww |grep [f]oo |tr ' ' '\n' |grep 'CWD=' to get foo's CWD. It works on a (non-gnu ps) aix, on a (gnu-ps) linux, but it fails in cygwin :( And on solaris you need to invoque /usr/ucb/ps to get the right ps. So probably non-posix? – Olivier Dulac Nov 20 '19 at 14:12
  • 1
    @OlivierDulac ps is perhaps the classic Unix command that's diverged the most between Unix variants. It has tended to converge recently, but POSIX only standardizes a few SysV-style options, and none of them give the current directory. Your command doesn't work, did you mean PWD= rather than CWD=? That doesn't actually give you the CWD, that gives you the value of the PWD environment variable (or a false match due to approximate parsing), which is usually correct only if the program didn't change its current directory after being launched by a shell. – Gilles 'SO- stop being evil' Nov 20 '19 at 19:25
  • you are absolutely right, it is to get the PWD ( |grep 'PWD=') and only shows where the command was started "from" (ie, what the shell's PWD was when the command was launched). This is sometimes usefull (ie on old aix, it helps find the actual script's directory when ps only shows "./script", and BASH_SOURCE[@] isn't available), but indeed it won't give out the actual CWD of the script. Sorry, and thanks for the corrections. lsof seems the most portable bet for the question's needs. (I already had +1 your answer, but I'd double that now if I could ^^) – Olivier Dulac Nov 21 '19 at 10:25

I will contribute my own answer.

An option, in the context of interactive shell (the question focuses on this context), could be automatically maintaining a link à la /proc/$PID/cwd, using the automation opportunity Bash provides:

PROMPT_COMMAND="ln -sfT \$(pwd) ~/$LINK_NAME"

The f option is required, as the link will be frequently overridden. The T option is required, as otherwise it seems the f option does work properly.

Shells may be made cooperative, using this in ex., ~/.bashrc:

if [ -v CWD_LINK_NAME ]; then
   declare -r CWD_LINK_NAME
   function rm_cwd_link() {
      rm "$CWD_LINK_NAME"
   trap rm_cwd_link EXIT

A shell or a terminal may be executed with CWD_LINK_NAME set to any relevant value. Ex. CWD_LINK_NAME="~/$SOME_ROLE_NAME" gnome-terminal

Another alternative, is using the same concept to track the pear working directory in a variable, this tracking being based on both @Gilles and @enedil contributions:

PROMPT_COMMAND="PEAR_WD=\$(lsof -p $PID | awk '/cwd/{print \$9}')"

However, this is less accurate and less handy, while it may still be the only way for the rare cases the $PROMPT_COMMAND cannot be set in the other shell.

I'm in favour of the first option (still waiting before selecting an answer, if ever there are other contributions to come).

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.