3

I'd rather not parse STDERR, but I can't think of another way to tell the difference, programmatically, between the two:

$ ls /net/foo.example.com/bar/test
/net/foo.example.com/bar/test: Permission denied
$ ls /sdfsdf
/sdfsdf: No such file or directory

No matter what command I try, they both seem to return the same error code, so that's a dead-end:

$ ls /net/foo.example.com/bar/test
/net/foo.example.com/bar/test: Permission denied
$ echo $?
2
$ ls /sdfsdf
/sdfsdf: No such file or directory
$ echo $?
2

I've tried the various file tests in perl, but they both return the same codes as well.

wsaxton
  • 195
  • 11

3 Answers3

9

Test the file instead.

test -e /etc/shadow && echo The file is there

test -f /etc/shadow && echo The file is a file

test -d /etc/shadow && echo Oops, that file is a directory

test -r /etc/shadow && echo I can read the file

test -w /etc/shadow && echo I can write the file

See the test man page for other possibilities.

Michael Hampton
  • 244,070
  • 43
  • 506
  • 972
  • 1
    I was very excited when I saw this but...it looks like I have another issue. The file I'm testing is through a /net mount point and 'test' does not work like it does on a local file! (Updated the example) – wsaxton May 20 '14 at 20:29
  • 2
    How does it "not work"? Do you even have access to the share at all? – Michael Hampton May 20 '14 at 20:31
  • On second thought, test does work. The problem is if I try to access a file BELOW the directory that you get permission denied on. I'm guessing that, since you don't have permission @ the top-level, you really don't know if the file exists or not so, therefore, it presumes it doesn't exist and gives you the same code. – wsaxton May 20 '14 at 20:31
  • 1
    That's correct, and that's how it should work. Otherwise I could guess file names and get sensitive data. `test -e /home/colleague/ComplaintAboutMe.doc` would leak info. – ceejayoz May 20 '14 at 20:32
  • 1
    @MichaelHampton yes, I have permissions to access the share 2 directories above (/net/foo.example.com) but get permission denied on /net/foo.example.com/bar as well as /net/foo.example.com/bar/test. The former returns 0. The latter returns 1. Therefore, I think its working as intended and that your answer is correct. – wsaxton May 20 '14 at 20:33
1

The other answers don't really distinguish between the different cases, but this perl script does:

$ cat testscript
chk() {
   perl -MErrno=ENOENT,EACCES -e '
      exit 0 if -e shift;        # exists
      exit 2 if $! == ENOENT;    # no such file/dir
      exit 3 if $! == EACCES;    # permission denied
      exit 1;                    # other error
   ' -- "$1"
   printf "%s %s  " "$?" "$1"
   [[ -e "$1" ]] && echo "(exists)" || echo "(DOES NOT EXIST)"
}
chk /root
chk /etc/passwd/blah
chk /x/y/z
chk /xyz
chk /root/.profile
chk /root/x/y/z

$ ./testscript
0 /root  (exists)
1 /etc/passwd/blah  (DOES NOT EXIST)
2 /x/y/z  (DOES NOT EXIST)
2 /xyz  (DOES NOT EXIST)
3 /root/.profile  (DOES NOT EXIST)
3 /root/x/y/z  (DOES NOT EXIST)

See the stat(2) manpage for possible error codes.

jrw32982
  • 111
  • 2
1
$ test -f /etc/passwd
$ echo $?
0

$ test -f /etc/passwds
$ echo $?
1
ceejayoz
  • 32,910
  • 7
  • 82
  • 106