1

It seems zsh doesn't honor globs inside variable patterns, in ${var##$pat} parameter expansions:

$ zsh -c 'pat=/*; var=/etc/; echo "$var $pat"; echo "${var##$pat}"'
/etc/ /*
/etc/
# sh result: empty

However, if $pat does not contain *, zsh and sh behave similarly:

$ zsh -c 'pat=/; var=/etc/; echo "$var $pat"; echo "${var##$pat}"'
/etc/ /
etc/
# sh result: same

zsh --emulate sh gives, of course, sh-compatible results. But if I want to stay in zsh emulation, is there any setopt option that changes this behavior? I've looked (briefly) in the docs and I can't really find the reason for this difference.

usretc
  • 723
  • 4
  • 9
  • In zsh, a simple `echo $pat` would also not expand the pattern, so it would be odd if such an expansion occurs by default in the context you present here. The zsh way to activate wildcards in a variable is, i.e., `echo $~pat`. – user1934428 Aug 30 '21 at 11:24
  • My scenario is that I'm trying to write a portable script (which I did not mention in the question). – usretc Aug 30 '21 at 11:53
  • _portable_ in which way? Accross different zsh versions? Note that zsh had quite some changes during its history. – user1934428 Aug 30 '21 at 12:10
  • Portable on present-day machines – usretc Aug 30 '21 at 12:35
  • Given that most languages (in particular bash and zsh) are available on virtually every platform i am aware of, you could stick with one of those, and just not assume that you will have the most recent version available. If you really are paranoic about portability (for instance, it should run on a machine where you don't have the permission to install anything), you could develop in in POSIX shell and simply ignore zsh completely; `sh` should really be available everywhere. – user1934428 Aug 30 '21 at 13:21

1 Answers1

1

In zsh, variable contents will only be treated as a pattern if you ask for that, with a ${~spec} expansion or the (very broad and therefore slightly dangerous) GLOB_SUBST option:

pat=/*t
var=/etc/
print "${var##$pat}"
#=> /etc/
print "${var##$~pat}"
#=> c/
setopt glob_subst
print "${var##$pat}"
#=> c/

This is described in the zshexpn man page, in the section for string substitution expansion ${name/pattern/repl}.

Gairfowl
  • 2,226
  • 6
  • 9
  • I see; does `setopt GLOB_SUBST` also make `$pat` glob filenames (in `${var##$pat}`)? – usretc Aug 29 '21 at 15:13
  • I mean, it doesn't seem so from simple tests, but there is ambiguity to contend with – usretc Aug 29 '21 at 15:24
  • 1
    I cannot find an explicit manual reference about how that works, but the `Rules` section in the `zshexpn` man page indicates that filename expansion comes later than other expansions, so a variable will be treated as a string pattern in contexts that require a string pattern, and then later as a glob pattern in contexts that allow that. So for example each of the tildes in `v=/etc/*; p=/*c; print ${~v##$~p}` will have a different effect. NB: the Rules section literally has a (joke) warning about brain damage from reading them, so be careful :-). – Gairfowl Aug 29 '21 at 21:03