Is there a way to use a glob qualifier on an intermediate directory? At least, avoid symbolic links from being followed. For instance, with: % mkdir -p dir/dir2 % ln -s dir foo % touch {dir,dir/dir2}/file With recursive globbing, one can choose whether or not to follow symbolic links: % echo **/file dir/dir2/file dir/file % echo ***/file dir/dir2/file dir/file foo/dir2/file foo/file Without recursive globbing, * matches symbolic links: % echo */file dir/file foo/file But what if I don't want to match symbolic links? At the end of a pattern, (^@) can be used: % echo * dir foo % echo *(^@) dir but not inside a pattern: % echo *(^@)/file zsh: no matches found: *(^@)/file With EXTENDED_GLOB, I get both, like */file, because (...) is used here for grouping, not for a glob qualifier. % setopt EXTENDED_GLOB % echo *(^@)/file dir/file foo/file I would have expected the following to work, but doesn't. % echo (*(^@))/file dir/file foo/file The zshexpn(1) man page says: Glob Qualifiers Patterns used for filename generation may end in a list of qualifiers enclosed in parentheses. [...] What "patterns" means here is not clear. Above, one has (...) Matches the enclosed pattern. [...] ^^^^^^^ but it seems that this is not a pattern that can have a glob qualifier. I assume that except for the grouping exception and recursive globbing, this is because patterns are mainly string operations until the list of files before considering glob qualifiers is obtained. I'm wondering why the following is not accepted: % echo (*/)file zsh: bad pattern: (*/)file I think that (pat/) without a following # should match a single occurrence of pat/ (without following symbolic links, contrary to the case without parentheses). -- Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
[-- Attachment #1: Type: text/plain, Size: 2664 bytes --] you can do something like this: setopt NULL_GLOB typeset -a arr=(*(^@)) ls ${^arr}/file but I'm curious if there is any solution that doesn't require using an intermediate array Pier Paolo Grassi linkedin: https://www.linkedin.com/in/pier-paolo-grassi-19300217 founder: https://www.meetup.com/it-IT/Machine-Learning-TO Il giorno mer 10 lug 2019 alle ore 15:38 Vincent Lefevre <vincent@vinc17.net> ha scritto: > Is there a way to use a glob qualifier on an intermediate directory? > At least, avoid symbolic links from being followed. > > For instance, with: > > % mkdir -p dir/dir2 > % ln -s dir foo > % touch {dir,dir/dir2}/file > > With recursive globbing, one can choose whether or not to follow > symbolic links: > > % echo **/file > dir/dir2/file dir/file > > % echo ***/file > dir/dir2/file dir/file foo/dir2/file foo/file > > Without recursive globbing, * matches symbolic links: > > % echo */file > dir/file foo/file > > But what if I don't want to match symbolic links? > > At the end of a pattern, (^@) can be used: > > % echo * > dir foo > > % echo *(^@) > dir > > but not inside a pattern: > > % echo *(^@)/file > zsh: no matches found: *(^@)/file > > With EXTENDED_GLOB, I get both, like */file, because (...) is used > here for grouping, not for a glob qualifier. > > % setopt EXTENDED_GLOB > % echo *(^@)/file > dir/file foo/file > > I would have expected the following to work, but doesn't. > > % echo (*(^@))/file > dir/file foo/file > > The zshexpn(1) man page says: > > Glob Qualifiers > Patterns used for filename generation may end in a list of > qualifiers enclosed in parentheses. [...] > > What "patterns" means here is not clear. Above, one has > > (...) Matches the enclosed pattern. [...] > ^^^^^^^ > > but it seems that this is not a pattern that can have a glob qualifier. > I assume that except for the grouping exception and recursive globbing, > this is because patterns are mainly string operations until the list of > files before considering glob qualifiers is obtained. > > I'm wondering why the following is not accepted: > > % echo (*/)file > zsh: bad pattern: (*/)file > > I think that (pat/) without a following # should match a single > occurrence of pat/ (without following symbolic links, contrary > to the case without parentheses). > > -- > Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> > 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> > Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon) >
On 7/10/19, Pier Paolo Grassi <pierpaolog@gmail.com> wrote:
> you can do something like this:
>
> setopt NULL_GLOB
> typeset -a arr=(*(^@))
> ls ${^arr}/file
>
> but I'm curious if there is any solution that doesn't require using an
> intermediate array
There isn't.
--
Mikael Magnusson
On 2019-07-10 15:58:05 +0200, Pier Paolo Grassi wrote: > you can do something like this: > > setopt NULL_GLOB > typeset -a arr=(*(^@)) > ls ${^arr}/file > > but I'm curious if there is any solution that doesn't require using > an intermediate array This isn't even correct as there may be directories without the file inside them. Moreover, I was looking for something short to type, and possibly compatible with completion widgets, such as expand-or-complete. Otherwise, there would be a solution to use a function that does what I want, of the form $(dirfile 'dirpattern' 'filepattern') but this is not satisfactory. -- Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/> 100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/> Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
2019-07-12 10:20:23 +0200, Vincent Lefevre: > On 2019-07-10 15:58:05 +0200, Pier Paolo Grassi wrote: > > you can do something like this: > > > > setopt NULL_GLOB > > typeset -a arr=(*(^@)) > > ls ${^arr}/file > > > > but I'm curious if there is any solution that doesn't require using > > an intermediate array > > This isn't even correct as there may be directories without the file > inside them. > > Moreover, I was looking for something short to type, and possibly > compatible with completion widgets, such as expand-or-complete. > Otherwise, there would be a solution to use a function that does > what I want, of the form $(dirfile 'dirpattern' 'filepattern') > but this is not satisfactory. [...] I raised a similar query on the zsh-workers mailing list at https://www.zsh.org/mla/workers/2019/msg00501.html There was no feedback though. -- Stephane
2019-07-10 18:26:42 +0200, Mikael Magnusson: > On 7/10/19, Pier Paolo Grassi <pierpaolog@gmail.com> wrote: > > you can do something like this: > > > > setopt NULL_GLOB > > typeset -a arr=(*(^@)) > > ls ${^arr}/file > > > > but I'm curious if there is any solution that doesn't require using an > > intermediate array > > There isn't. [...] Well, there is ls -d -- (*/)##file~*/*/* (a corrected version of the one I suggested in my related zsh-workers thread at https://www.zsh.org/mla/workers/2019/msg00501.html). But I wouldn't call it "a solution". That works because (*/)## doesn't follow symlinks, but obviously that means crawling the whole directory tree while we only care for depth 1. -- Stephane