Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How POSIX compliant is "/path/file/.."?

Tags:

bash

posix

sh

cd

ash

I wanted to change current directory into shell script into directory, containing specific regular file. I found that following trick works in mksh and busybox sh:

path=/path/to/regular/file
cd $path/.. 

but not in GNU Bash:

bash: cd: /path/to/regular/file/..: Not a directory

Is this trick not posix-compatible, or Bash is too pedantic?

like image 388
KAction Avatar asked Jun 14 '20 03:06

KAction


1 Answers

Latest edition of the standard doesn't allow that. POSIX.1-2017 cd spec. says that if the pathname component preceding dot-dot is not a directory, cd shall consider that an error.

From cd § DESCRIPTION - step 8.b:

b. For each dot-dot component, if there is a preceding component and
   it is neither root nor dot-dot, then:

    i. If the preceding component does not refer (in the context of
       pathname resolution with symbolic links followed) to a
       directory, then the cd utility shall display an appropriate
       error message and no further steps shall be taken.

When cd is invoked with -P option, this step is omitted; but then chdir() fails if one of the pathname components names an existing file that is neither a directory nor a symbolic link to a directory.

Besides, permitting that trick also allows inconsistent behavior in cd. For example, when run in a directory containing a regular file named bar, and a directory named foo containing another directory named bar, the following two commands do different things in a shell where cd ignores non-directory components preceding a dot-dot, despite that CDPATH contains the empty string (i.e. the current working directory) in both cases.

CDPATH= cd bar/..
CDPATH=:foo cd bar/..

Below transcripts visualize the difference between non-conforming and conforming implementations clearly.

$ tree -F
.
├── bar
└── foo/
    └── bar/

2 directories, 1 file
$ ash
$ CDPATH= cd bar/..
$ pwd
/home/oguz
$ CDPATH=:foo cd bar/..
/home/oguz/foo
$ bash
$ CDPATH= cd bar/..
bash: cd: bar/..: Not a directory
$ CDPATH=:foo cd bar/..
/home/oguz/foo

bosh, gwsh, ksh93u+m, and yash are other actively maintained shells that implement the same behavior as bash.

like image 75
oguz ismail Avatar answered Nov 13 '22 16:11

oguz ismail