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.


$ 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).


$ find -L . -perm -o=w
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

	  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
gfind: ‘./s2’: Permission denied
$ busybox find . -follow -perm -o=w
find: ./s3: Not a directory
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).


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