4

I am trying to develop a script which runs (and, ideally, does the same :-) ) in zsh and Bash. Problem is, that at a point, the zsh-specific part contains a pattern ending with (N). So: this_pattern*(N). In zsh, that makes the pattern expand to nothing if it has no match.

Bash says for that, "syntax error by unexpected symbol". Note, execution on Bash never happens on this zsh-specific part, and this error message is caused by the parsing code!

Could I somehow help Bash to eat it, for example to not parse it?

3
  • By the way, in your user profile, the "The Last Question" link is dead. You might want to use web.archive.org/web/20191221200207/https://www.multivax.com/… instead. Jul 18 at 11:18
  • Btw, what do you do in the Bash-specific branch then? The issue that comes from a non-matching glob pattern expanding to itself is equally there in both shells, and some of the workarounds in Bash would also work directly in zsh.
    – ilkkachu
    Jul 21 at 8:16
  • Also, I suspect the actual error you get is "syntax error near unexpected token '('" (maybe with a backtick as the opening quote, gah). I can't be sure sure, though, so I won't edit. It often helps to copy the exact error message to the post, since it can help differentiate between multiple issues in case there's doubt for whatever reason. Probably not here, as it's quite clear the ( operator there causes a syntax error, but in any case.
    – ilkkachu
    Jul 21 at 8:20

2 Answers 2

5

From zsh_expn:

  N      sets the NULL_GLOB option for the current pattern

So, the bash way would be to set the nullglob option for that pattern.

( shopt -s nullglob || setopt NULL_GLOB && yourcommand this_pattern* )

would work, and set that option just for the subshell spawned by (…). (Either shopt or setopt fails, being a bash and zsh built-in, respectively, but the one that does work sets the option to make patterns without matches disappear without error. && and || have left-to-right evaluation.)

Note that of course this lacks beauty (sorry, @StéphaneChazelas!), and subshell creation comes at a performance penalty. But you want portability, so you can't really use a zsh-specific feature.

10
  • What is setopt? Jul 18 at 12:56
  • Exactly that is what does not work. Until (N) is in the script, and it must be in the script to work in zsh, bash will eject with failure. The question was not, how to make a (N) in bash.
    – peterh
    Jul 18 at 13:50
  • but you can do exactly the same that (N) does with setopt in zsh. What am I missing here? There's simply no way to make (N) work in bash, bash's expansion is not powerful enough for that. Jul 18 at 14:44
  • (btw, what I actually did, was this: [ -v BASH_VERSION ] && shopt -s nullglob || setopt + NULL_GLOB. Yes it loses the original nullglob value but it is not a problem in my case.)
    – peterh
    Jul 19 at 4:56
  • 1
    Note that ksh93 doesn't use forks for subshell environments, it saves and restores the state instead. ksh93, ash and zsh can set options locally without using a subshell; zsh also has anonymous functions. Newer versions of bash can also set options locally à la ash, but only for the options set with set -o, not the ones set with shopt. Jul 21 at 9:05
4

If it's in a zsh-specific part, you can avoid bash complaining upon parsing that code that it will never run by doing:

eval 'cmd this_pattern*(N)'

instead of

cmd this_pattern*(N)

That eval command is valid in bash from a syntax PoV. It would only become invalid if eval was run in which case it would try to interpret the cmd this_pattern*(N) code that is invalid in bash.

Now, in this specific case,

cmd this_pattern*(N)

Is actually valid in bash (though means something completely different) if you enable the extglob option, upon which bash recognises a subset of ksh's extended glob operator including *(something) meaning 0 or more somethings.

So doing:

if [ -n "$BASH_VERSION" ]; then
  shopt -s extglob
fi

beforehand would avoid the parsing error in bash in this case. It wouldn't help for a *.txt(N) pattern for instance though.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .