3

I am teaching myself bash scripting with the book 'Learning the Bash Shell' by Newbam. I'm getting on OK with the book, but am a bit confused by the following script. It is a script which uses a for loop to go through the directories in $PATH, and print out information about them. The script is

IFS=:
for dir in $PATH; do
 if [ -z "$dir" ]; then dir=.; fi
 if ! [ -e "$dir" ]; then
 echo "$dir doesn't exist"
 elif ! [ -d "$dir" ]; then
 echo "$dir isn't a directory"
 else
  ls -ld $dir
done

What I'm confused about is why if dir is zero, or doesn't exist, are we then setting this null value to be the current directory? Or are we changing dir to our current directory (whatever directory we happen to be in) ? The script then seems to test if dir exists, and then tests if it is a directory.

Can anybody shed light on this aspect of the script for me? I would have thought that if [ -z "$dir" ] was true, that this would indicate that the directory doesn't exist, and isn't a directory to begin with?

1
  • 1
    To bash "." and the empty field in the PATH are synonym to the "current directory".
    – Emmanuel
    Commented Sep 4, 2015 at 11:38

4 Answers 4

4

The -z test is testing for a zero-length value in $dir, not for anything related to an actual directory. That condition is triggered if you have a :: sequence in your PATH variable, at which point we set the value of the $dir variable to ., meaning the current directory, and we then conduct the standard two tests on it.

3
  • Thanks. Still can't quite see the logic of performing tests on our current directory when the aim of the script was to test specifically directories in PATH
    – John D
    Commented Sep 4, 2015 at 12:38
  • If there is an empty directory in PATH, it means the current directory is in the PATH. :: in $PATH is shorthand for :.:.
    – John
    Commented Sep 4, 2015 at 12:39
  • Not just ::, but PATH=:foo:bar and PATH=foo:bar: are paths beginning with and ending with, respectively, the current directory.
    – chepner
    Commented Sep 5, 2015 at 12:23
1

If $dir is empty (-z test) then $dir is set to . (current directory where you launched the script).

Now guess that your $PATH is malformed like PATH=/bin::/usr/bin:/usr/local/bin At second rank you have an empty field. So when the field is empty, it is replaced by the current directory from where is launched the script (then dir=.).

2
  • Thanks for reply. But aren't we then performing the test on a random directory ( the one we happened to be in when we ran script) rather than a directory in PATH? Sorry for being slow on the uptake with this
    – John D
    Commented Sep 4, 2015 at 11:57
  • Exact you guess it right !
    – netmonk
    Commented Sep 4, 2015 at 12:00
0

maybe there is a elif (else if) missing.

however, this scripts aims to list $dir contents, but first make sure

  1. $dir exists if ! [ -e "$dir" ]
  2. $dir is a dir, not a file, pipe, dev elif ! [ -d "$dir" ]

thoses test cannot be made with empty value for $dir, so first line ( if [ -z "$dir" ]; then dir=.; fi ) is used to relace empty string by . which is a dir and exists.

empty $dir string can be make two ways

  • PATH=/usr/bin:/sbin::$HOME/bin
  • PATH=/usr/bin:/sbin:$MYAPPBINDIR:$HOME/bin (where $MYAPPBINDIR is empty).
0

From the POSIX specification for PATH (you'll have to scroll down a bit):

(emphasis mine)

PATH

This variable shall represent the sequence of path prefixes that certain functions and utilities apply in searching for an executable file known only by a filename. The prefixes shall be separated by a ( ':' ). When a non-zero-length prefix is applied to this filename, a shall be inserted between the prefix and the filename if the prefix did not end in . A zero-length prefix is a legacy feature that indicates the current working directory. It appears as two adjacent characters ( "::" ), as an initial preceding the rest of the list, or as a trailing following the rest of the list. A strictly conforming application shall use an actual pathname (such as .) to represent the current working directory in PATH. The list shall be searched from beginning to end, applying the filename to each prefix, until an executable file with the specified name and appropriate execution permissions is found. If the pathname being sought contains a , the search through the path prefixes shall not be performed. If the pathname begins with a , the specified path is resolved (see Pathname Resolution). If PATH is unset or is set to null, the path search is implementation-defined. Since is a separator in this context, directory names that might be used in PATH should not include a character.

My assumption is that the POSIX spec accepts the empty string to accommodate systems which did not use ., or did not have any special name, as a name for the current working directory.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .