85

I encountered BASEDIR=$(pwd) in a script.

Are there any advantages or disadvantages over using BASEDIR="$PWD", other than maybe, that $PWD could be overwritten?

Minix
  • 5,855
  • 5
    some info at http://unix.stackexchange.com/a/79621 – Stéphane Chazelas Dec 12 '14 at 11:19
  • @StéphaneChazelas Very interesting write up. I'm only halfway through and will continue, but as far as I understood it, it's better to use $(pwd), because $PWD can become outdated in certain circumstances. – Minix Dec 12 '14 at 11:51
  • 3
    only in some shells (not bash, dash, zsh or ksh93 for instance) will pwd potentially give you less stale information than $PWD in some corner cases. $(pwd) on the other hand doesn't work if the current directory ends in newline characters, means forking a process (except in ksh93) and use extra resources. My view is use $PWD of $(pwd -P), it's not worth using $(pwd). – Stéphane Chazelas Dec 12 '14 at 11:59
  • 2
    at the bottom there stephane mentions using cd -P -- "$dir". if there is any doubt about the value of $PWD you can always cd -P . first. this may also be beneficial in that you also get whatever $PWD was before that in $OLDPWD and so can compare them afterward - and the next cd ...; cd - sequence will be sure to bring you back to where you are now. – mikeserv Dec 12 '14 at 12:57

2 Answers2

101

If bash encounters $(pwd) it will execute the command pwd and replace $(pwd) with this command's output. $PWDis a variable that is almost always set. pwd is a builtin shell command since a long time.

So $PWD will fail if this variable is not set and $(pwd) will fail if you are using a shell that does not support the $() construct which is to my experience pretty often the case. So I would use $PWD.

As every nerd I have my own shell scripting tutorial

Anthon
  • 79,293
  • 8
    I was under the impression that the \command`` syntax was undesirable and $(command) is to be preferred. As far as I know the latter is POSIX compliant, but I'm not 100% sure. – Minix Dec 12 '14 at 11:51
  • 7
    @Minix The $() is indeed specified by POSIX so outside the pre POSIX /bin/sh available on Solaris 10 and older and csh derived shells, I doubt many other mainstream shells lack that feature. – jlliagre Dec 12 '14 at 11:55
  • @Minix: Here is a recent question on this site that illustrates one problem with using backticks instead of $() – PM 2Ring Dec 12 '14 at 12:48
  • 1
    correct, instead of $() you could use backticks, but this will not be cascadable so I did not mention it – Thorsten Staerk Dec 12 '14 at 19:23
  • 1
    Nice minimap on your tutorial.... – cvsguimaraes Mar 31 '16 at 03:30
  • I am also considering which of $(pwd) vs $PWD is more reliable. As $PWD is a variable that could be changed to arbitrary value, I thought $(pwd) is more reliable that it equals to the actual current working directory. For example cd /home ; PWD=/tmp ; ls lists the files in /home, not /tmp. On the other hand, if $() is not supported, most scripts will fail too, isn't it? I am not an expert of Shell Scripts. Please comment if my thoughts are correct. Thank you. – midnite Dec 27 '23 at 14:57
  • @midnite - $(pwd) has always worked for me in bash. I have made good experience with making sure the script is run on bash (with the shebang #!/bin/bash) and then using $(pwd). The idea of using a variable that can be changed anyhow feels just wrong to me. – Thorsten Staerk Jan 21 '24 at 05:56
17

It should also be mentioned that $PWD is desirable because of its performance. As a shell variable, it can be resolved almost instantly. $(pwd) is a bit more confusing. If you inspect man 1 bulitin on a system with Bash, you'll see that pwd is a built-in command, which may lead you to believe that it will be just as fast as accessing a variable. However, the $() construct always launches a new subshell (a new process) to run its contents, regardless of what's inside. The same thing goes for backticks. Indeed, when I benchmark it:

echo 'Benchmarking $(pwd)...'
time (for i in {1..1000}; do echo $(pwd) > /dev/null; done)
echo 'Benchmarking $PWD...'
time (for i in {1..1000}; do echo $PWD > /dev/null; done)

I get 1.52 seconds for the $(pwd) call and 0.018 seconds for $PWD. Unnecessary launching of subshells, as well as any other extraneous processes, should be avoided whenever possible. They're much more expensive than function calls that you may be used to in other languages.

  • That's an interesting take on it, but I don't know if I am concerned about performance on my shell scripts. I also wonder how the performance would change, if the pwd changes in between querying it. – Minix Sep 09 '18 at 19:30
  • 1
    @Minix I modified my script to have the loop body be echo $PWD; pushd ..; echo $PWD; popd (with additional >/dev/null after each statement), and it takes 0.05 seconds. I then removed the echo statements (only pushd/popd) and it took 0.03. So the time per echo $PWD was still 0.01 seconds or so. I did something similar with $(pwd), and it took 2.2 seconds for each loop, so 1.1 seconds per $(pwd) call. – markasoftware Sep 10 '18 at 01:26
  • Not to be too picky, but I can imagine, that the computation, that would replace $PWD would be done in the background before the evaluation of the echo statements. But clearly, accessing $PWD is still significantly faster, so if compatibility is not a concern, this is definitely a reason to pick one over the other. Thanks for the work in testing this so thoroughly. :) – Minix Sep 10 '18 at 10:37