Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: glob qualifier '-' doesn't work correctly on dangling symlinks



2020-04-12 04:17:22 +0200, Vincent Lefevre:
[...]
> > What would be the glob qualifier syntax for broken symlinks?
> 
> There would need something for that. But even currently, there
> are things one cannot do with glob qualifiers, such as one does
> not have a way to know the reason why a symlink is broken, which
> can be important when one is interested in broken symlinks.
> 
> zira% ln -s /does-not-exist s1
> zira% ln -s /root/foo s2
> zira% ls -L s*
> ls: cannot access 's1': No such file or directory
> ls: cannot access 's2': Permission denied
> 
> But with glob qualifiers, there does not seem to be a way to
> distinguish these two cases.
[...]

There's:

$ zmodload zsh/system
$ ls -ld -- *(e[ERRNO=0]-e['[[ $errnos[ERRNO] = EACCES ]]'])
lrwxrwxrwx 1 chazelas chazelas 9 Apr 12 07:34 s2 -> /root/foo
$ ls -ld -- *(e[ERRNO=0]-e['[[ $errnos[ERRNO] = ENOENT ]]'])
lrwxrwxrwx 1 chazelas chazelas 15 Apr 12 07:34 s1 -> /does-not-exist

(the ERRNO=0 may not be necessary).

Note:

$ find -L . -perm -o=w
./s1
find: ‘./s2’: Permission denied

But again, *(-@) for broken symlinks is documented and widely
used, we can't break that.

So if we change "-" to exclude broken symlinks, we'd need to
special case -@. What's the scope of what should be special
cased? *(-@e['((count++))']) should probably still work as well
for instance.

How about: *(-e['((n++))']@['((brokenlinks++))'])?

And *(-@m-1) (broken links created in the last 24 hours, though
I'd expect one to write *(m-1-@) instead here)

Note that for "find -L", zsh's current behaviour is required by
POSIX (at least for links whose target can be determined not to
exist):

     -L
	  Cause the file information and file type evaluated for
	  each symbolic link encountered as a path operand on
	  the command line or encountered during the traversal
	  of a file hierarchy to be those of the file referenced
	  by the link, and not the link itself. If the
	                                        ^^^^^^
	  referenced file does not exist, the file information
	  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
	  and type shall be for the link itself.
	  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I find some variation in behaviour though:

$ ln -s /etc/passwd/foo s3
$ gfind . -follow -perm -o=w
gfind: ‘./s3’: Not a directory
./s3
./s1
gfind: ‘./s2’: Permission denied
$ busybox find . -follow -perm -o=w
find: ./s3: Not a directory
./s1
find: ./s2: Permission denied
$ find_su3 . -follow -perm -o=w
find_su3: cannot follow symbolic link ./s3: Not a directory
find_su3: cannot follow symbolic link ./s1: No such file or directory
find_su3: cannot follow symbolic link ./s2: Permission denied

(the latter from the heirloom toolchest being not POSIX compliant)

In any case, in */*(W), or ***/*(W) or **/*(W), the cases where
directories are not readable or searchable, or symlink targets
not accessible are always silently ignored (as opposed to the
find equivalents).

-- 
Stephane



Messages sorted by: Reverse Date, Date, Thread, Author