zsh-users
 help / color / mirror / code / Atom feed
* zmv exits from function
@ 2023-12-30 17:42 Ray Andrews
  2023-12-30 20:38 ` Bart Schaefer
  2023-12-30 22:34 ` Bart Schaefer
  0 siblings, 2 replies; 25+ messages in thread
From: Ray Andrews @ 2023-12-30 17:42 UTC (permalink / raw)
  To: Zsh Users

I'm using zmv to rename files in a directory tree recursively via a 
'for' loop which visits each subdirectory.  It works fine if there are 
files found to rename, but if not, then the entire function crashes back 
to CL.  How can I persuade zmv to just let the function cycle to the 
next subdir?  I see no option that seems relevant.

Cut down to the essentials:

function global ()
{
     f ,dB >! /tmp/global_tmp    # My function.  Gives list of subdirs, 
works fine.
     curdir=$PWD
     for aa in $(cat /tmp/global_tmp); do     # For every line:

         cd $aa

         zmv '(*).SNT' '$1.eml'
         zmv '(*).MES' '$1.eml'

         cd $curdir
     done
}

Lots of other test commands in place of zmv cycle fine in case of no 
match, but zmv insists on returning.




^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 17:42 zmv exits from function Ray Andrews
@ 2023-12-30 20:38 ` Bart Schaefer
  2023-12-30 21:02   ` Ray Andrews
                     ` (2 more replies)
  2023-12-30 22:34 ` Bart Schaefer
  1 sibling, 3 replies; 25+ messages in thread
From: Bart Schaefer @ 2023-12-30 20:38 UTC (permalink / raw)
  To: Ray Andrews; +Cc: Zsh Users

[-- Attachment #1: Type: text/plain, Size: 923 bytes --]

On Sat, Dec 30, 2023 at 9:43 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> I'm using zmv to rename files in a directory tree recursively via a
> 'for' loop which visits each subdirectory.  It works fine if there are
> files found to rename, but if not, then the entire function crashes back
> to CL.  How can I persuade zmv to just let the function cycle to the
> next subdir?

zmv forces zsh emulation which means the nomatch option is in effect,
and you can't change that without editing the zmv source.

Just run the zmv in a subshell:

  ( zmv '(*).SNT' '$1.eml' )
  ( zmv '(*).MES' '$1.eml' )

Also make sure that you don't have the errr_exit or err_return setopts
in effect or the loop will break even with the subshells.

Alternately you could test whether the pattern matches any files
before calling zmv in the first place.

Arguably zmv could use null_glob.  Thoughts from -workers?

[-- Attachment #2: zmv-nullglob.txt --]
[-- Type: text/plain, Size: 513 bytes --]

diff --git a/Functions/Misc/zmv b/Functions/Misc/zmv
index 269fe5ba5..51c8ad3ab 100644
--- a/Functions/Misc/zmv
+++ b/Functions/Misc/zmv
@@ -236,12 +236,14 @@ if [[ $pat = (#b)(*)\((\*\*##/)\)(*) ]]; then
 else
   fpat=$pat
 fi
-files=(${~fpat})
+files=(${~fpat}(#qN))
 
 [[ -n $hasglobqual ]] && pat=$opat
 
 errs=()
 
+[[ -n $files ]] || errs=( "no files matched \`$fpat'" )
+
 for f in $files; do
   if [[ $pat = (#b)(*)\(\*\*##/\)(*) ]]; then
     # This looks like a recursive glob.  This isn't good enough,

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 20:38 ` Bart Schaefer
@ 2023-12-30 21:02   ` Ray Andrews
  2023-12-30 22:21     ` Bart Schaefer
  2023-12-30 21:15   ` Mikael Magnusson
  2024-01-02 11:50   ` Peter Stephenson
  2 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2023-12-30 21:02 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 601 bytes --]


On 2023-12-30 12:38, Bart Schaefer wrote:
> Just run the zmv in a subshell:
>
>    ( zmv '(*).SNT' '$1.eml' )
>    ( zmv '(*).MES' '$1.eml' )
>
Perfect :-)
> Arguably zmv could use null_glob.  Thoughts from -workers?

That's that option that makes everything grind to a halt if nothing if 
found?  Think I recall that " (N) " setting to cope with it?  From a 
users point of view it just makes trouble where no trouble really 
exists.  BTW, I did look at the source and noticed no return values, I 
had thought that something like ' zmv ... && echo "Success" || echo 
"Nope"' ... might catch it.


[-- Attachment #2: Type: text/html, Size: 1272 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 20:38 ` Bart Schaefer
  2023-12-30 21:02   ` Ray Andrews
@ 2023-12-30 21:15   ` Mikael Magnusson
  2023-12-31  3:43     ` Ray Andrews
  2024-01-02 11:50   ` Peter Stephenson
  2 siblings, 1 reply; 25+ messages in thread
From: Mikael Magnusson @ 2023-12-30 21:15 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Ray Andrews, Zsh Users

On 12/30/23, Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Sat, Dec 30, 2023 at 9:43 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>>
>> I'm using zmv to rename files in a directory tree recursively via a
>> 'for' loop which visits each subdirectory.  It works fine if there are
>> files found to rename, but if not, then the entire function crashes back
>> to CL.  How can I persuade zmv to just let the function cycle to the
>> next subdir?
>
> zmv forces zsh emulation which means the nomatch option is in effect,
> and you can't change that without editing the zmv source.
>
> Just run the zmv in a subshell:
>
>   ( zmv '(*).SNT' '$1.eml' )
>   ( zmv '(*).MES' '$1.eml' )

You can also do this:
  { zmv '(*).SNT' '$1.eml' } always { TRY_BLOCK_ERROR=0 }

I have this aliased as
  alias always_continue='always { TRY_BLOCK_ERROR=0 }'
which lets you do the slightly neater
  { zmv '(*).SNT' '$1.eml' } always_continue

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 21:02   ` Ray Andrews
@ 2023-12-30 22:21     ` Bart Schaefer
  0 siblings, 0 replies; 25+ messages in thread
From: Bart Schaefer @ 2023-12-30 22:21 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sat, Dec 30, 2023 at 1:02 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
>
> On 2023-12-30 12:38, Bart Schaefer wrote:
> >
> > Arguably zmv could use null_glob.  Thoughts from -workers?
>
> That's that option that makes everything grind to a halt if nothing if found?

No, you're thinking of nomatch, which as I said is already in effect
and causing the result that you see.  The null_glob option supersedes
no_match and makes globs that don't match anything disappear without
an error.  This is in contrast to the no_nomatch option which leaves
the glob un-expanded but does not remove it.  Setting null_glob
globally can be dangerous because it can leave a command with no
arguments at all or with its arguments in a different order than
expected.

> Think I recall that " (N) " setting to cope with it?

The (N) glob qualifier turns ON null_glob to override no_match, yes.
That's the suggested amendment to zmv for which I'm asking -workers
opinion.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 17:42 zmv exits from function Ray Andrews
  2023-12-30 20:38 ` Bart Schaefer
@ 2023-12-30 22:34 ` Bart Schaefer
  1 sibling, 0 replies; 25+ messages in thread
From: Bart Schaefer @ 2023-12-30 22:34 UTC (permalink / raw)
  To: Ray Andrews; +Cc: Zsh Users

On Sat, Dec 30, 2023 at 9:43 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> I'm using zmv to rename files in a directory tree recursively via a
> 'for' loop which visits each subdirectory.

Incidentally, unless your "f" function is doing something non-obvious,
zmv can recursively search directories all by itself.

Try (without your "for" wrapper and all the "cd"-ing):

  zmv -n '(*/)#(*).(SNT|MES)' '$1$2.eml'

If that looks like it would do the right thing, remove the "-n".


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 21:15   ` Mikael Magnusson
@ 2023-12-31  3:43     ` Ray Andrews
  2023-12-31  3:58       ` Bart Schaefer
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2023-12-31  3:43 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2083 bytes --]


On 2023-12-30 13:15, Mikael Magnusson wrote:
> You can also do this:
>    { zmv '(*).SNT' '$1.eml' } always { TRY_BLOCK_ERROR=0 }

Sheesh, of course I'm no expert, still I've never seen any such 
construction before.  Always new domains of syntax to study.  So when 
zmv quits, crashing out of the function is not immediate -- there is 
further parsing, thus this 'always' word is handled. Interesting.

On 2023-12-30 12:38, Bart Schaefer wrote:

> Arguably zmv could use null_glob.  Thoughts from -workers?

That's that option that makes everything grind to a halt if nothing if found?

> No, you're thinking of nomatch, which as I said is already in effect
and causing the result that you see.  The null_glob option supersedes
no_match and makes globs that don't match anything disappear without
an error.

Yeah, for some unknown reason I said it backwards -- I know that (N) smooths continuation of flow, it doesn't break it.

> This is in contrast to the no_nomatch option which leaves
the glob un-expanded but does not remove it.

I've run into that, and it can be ugly -- literal asterisks being fed to some command that doesn't want them.  It's good to understand what's going down there.

   Setting null_glob
globally can be dangerous because it can leave a command with no
arguments at all or with its arguments in a different order than
expected.

Yes, another potential landmine.  What might be intuitive is some way of simply making a command 'stop', but that might not be so simple -- something that holds it's place, but has no value -- it 'counts' as an argument but has no content.  It's so dumb when: "ls no-such-files.*" ends up listing everything in the directory rather than nothing.  Dunno who thought that was a good idea.


>  zmv -n '(*/)#(*).(SNT|MES)' '$1$2.eml'

If that looks like it would do the right thing, remove the "-n".

I'll give it a go.  So much can be done with all that globbing functionality.  Such power.  But I can never remember that tersest of all terse syntaxes -- gotta make myself a cheat sheet including a page full of examples.


[-- Attachment #2: Type: text/html, Size: 2860 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-31  3:43     ` Ray Andrews
@ 2023-12-31  3:58       ` Bart Schaefer
  2023-12-31 15:53         ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2023-12-31  3:58 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sat, Dec 30, 2023 at 7:43 PM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
>   { zmv '(*).SNT' '$1.eml' } always { TRY_BLOCK_ERROR=0 }
>
> So when zmv quits, crashing out of the function is not immediate -- there is further parsing

No, the parsing is all done first: "{ ... } always { ... }" is a full
expression.  Zsh "knows" the always-part is coming before it even
starts executing the first block.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-31  3:58       ` Bart Schaefer
@ 2023-12-31 15:53         ` Ray Andrews
  2023-12-31 21:44           ` Bart Schaefer
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2023-12-31 15:53 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 635 bytes --]


On 2023-12-30 19:58, Bart Schaefer wrote:
> No, the parsing is all done first: "{ ... } always { ... }" is a full
> expression.
Zsh "knows" the always-part is coming before it even
> starts executing the first block.
>
So that's multi-pass parsing.  Anyway, first I've seen of anything like 
it.  I'm reading up on it right now.  'always' is a reserved word then.  
Bottom line is that I now have a tool for handling 'no files' 
situations.  Good to know because there could be any number of 
housekeeping functions that might want to clean up or rename some group 
of files if they exist but it's not a problem if they don't.



[-- Attachment #2: Type: text/html, Size: 1368 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-31 15:53         ` Ray Andrews
@ 2023-12-31 21:44           ` Bart Schaefer
  2023-12-31 22:06             ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2023-12-31 21:44 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Sun, Dec 31, 2023 at 7:53 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> So that's multi-pass parsing.

Again, no.  It's only parsed once, into an internal format
(essentially, the same format used for "zcompile" files) and then
executed if syntactically correct.  The only way to get another parse
is to use "eval".

Expansion and word splitting on can occur during execution, but that
doesn't change the syntax tree.  Parsing does happen inside command
substitution but is limited to that syntactic scope.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-31 21:44           ` Bart Schaefer
@ 2023-12-31 22:06             ` Ray Andrews
  2024-01-02 14:51               ` Mark J. Reed
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2023-12-31 22:06 UTC (permalink / raw)
  To: zsh-users


On 2023-12-31 13:44, Bart Schaefer wrote:
> On Sun, Dec 31, 2023 at 7:53 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>> So that's multi-pass parsing.
> Again, no.  It's only parsed once

I don't have the background to understand it and it's probably not worth 
your time to make it clear.  It 'look's like' a multiple parsing -- 
before zmv executes, it knows that errors will be handled differently 
than default due to following code, and then it 'goes back' and actually 
executes.  Or ... zmv returns innocently and then the next code rescues 
the function from aborting?  Nevermind, I don't need to know.  It's just 
sorta fuzzy trying to understand at exactly what point the function 
returns if zmv isn't happy.  I'm thinking in C naturally.





^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-30 20:38 ` Bart Schaefer
  2023-12-30 21:02   ` Ray Andrews
  2023-12-30 21:15   ` Mikael Magnusson
@ 2024-01-02 11:50   ` Peter Stephenson
  2024-01-02 17:08     ` Ray Andrews
  2 siblings, 1 reply; 25+ messages in thread
From: Peter Stephenson @ 2024-01-02 11:50 UTC (permalink / raw)
  To: Zsh Users

> On 30/12/2023 20:38 GMT Bart Schaefer <schaefer@brasslantern.com> wrote:
> Arguably zmv could use null_glob.  Thoughts from -workers?

I guess the right thing to do regardless of option is that it should
fail gracefully just by returning status 1 --- so not propagating the
error to the caller.  If the effect of NULL_GLOB is we loop over nothing,
that presumably gives us status 0?  I'd say we should probably detect that
as a (return status) failure for minimum surprises.

pws


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2023-12-31 22:06             ` Ray Andrews
@ 2024-01-02 14:51               ` Mark J. Reed
  2024-01-02 17:01                 ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Mark J. Reed @ 2024-01-02 14:51 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1414 bytes --]

On Sun, Dec 31, 2023 at 5:07 PM Ray Andrews <rayandrews@eastlink.ca> wrote:

>
> On 2023-12-31 13:44, Bart Schaefer wrote:
> > On Sun, Dec 31, 2023 at 7:53 AM Ray Andrews <rayandrews@eastlink.ca>
> wrote:
> >> So that's multi-pass parsing.
> > Again, no.  It's only parsed once
>
> I don't have the background to understand it and it's probably not worth
> your time to make it clear.
>

It's not parsed multiple times, but it _is parsed fully before anything
runs.  _Parsing_ is just reading the code and determining what it means;
actually _running_ it comes later. Zsh parses the whole expression before
it executes any part of it – it doesn't just stop and execute the first
thing that looks like a command. So it has already read the `always` block
and knows it's there before it executes the code to the left of it.

And the presence of the `always` doesn't affect parsing; the code on both
sides works the same way it would without the `always`. The only thing it
does is tell Zsh that, as long as the code on the left doesn't exit the
shell entirely, it doesn't matter what happens there; the code on the right
needs to get executed next. Even if the left code interrupts the normal
control flow with a `return` or `break` or `continue`, the code on the
right will get executed before the next thing, wherever that next thing is.

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 2012 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 14:51               ` Mark J. Reed
@ 2024-01-02 17:01                 ` Ray Andrews
  0 siblings, 0 replies; 25+ messages in thread
From: Ray Andrews @ 2024-01-02 17:01 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2399 bytes --]


On 2024-01-02 06:51, Mark J. Reed wrote:
>
> It's not parsed multiple times, but it _is parsed fully before 
> anything runs.  _Parsing_ is just reading the code and determining 
> what it means; actually _running_ it comes later. Zsh parses the whole 
> expression before it executes any part of it – it doesn't just stop 
> and execute the first thing that looks like a command. So it has 
> already read the `always` block and knows it's there before it 
> executes the code to the left of it.
That's what I meant.  Right tho -- it's handled in two passes but one is 
called  parsing, the second is called running.   But the parse sets a 
memo that zmv will not be permitted to crash the function at run time.
>
> And the presence of the `always` doesn't affect parsing; the code on 
> both sides works the same way it would without the `always`. The only 
> thing it does is tell Zsh that, as long as the code on the left 
> doesn't exit the shell entirely, it doesn't matter what happens there; 
> the code on the right needs to get executed next. Even if the left 
> code interrupts the normal control flow with a `return` or `break` or 
> `continue`, the code on the right will get executed before the next 
> thing, wherever that next thing is.

This appears to be established practice, but I must say, seeing it for 
the first time, it sure looks bizarre.  It looks like some hideous hack 
to handle a code flow discontinuity that might have had a more 
straightforward handling:

     zmv ...   ...

     if [ $? -eq 0 ]; then echo "Files found, files moved boss."; fi

     if [ $? -eq 1 ]; then echo "Ooops, no files found, but no problemo, 
keep calm and carry on.";  fi

     or:

     if [ $? -eq 1 ]; then echo "Ooops, no files found so this function 
won't have any more work to do so just return."; return; fi

     or:

     if [ $? -eq 1 ]; then echo "WARNING!, no files found!!  This is a 
major problem so crash the entire shell."; exit;  fi

... You guys know best however.  But everything I've learned prior to 
this issue would have me expect that if zmv can't do anything it simply 
returns and code flow continues.  I wonder why it can't be just that 
simple.  It could very well be that other zsh functions  have this 
'crash the calling function' property but it's the first time I've seen 
it.  (and zmv is soooo wonderful!)





[-- Attachment #2: Type: text/html, Size: 3659 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 11:50   ` Peter Stephenson
@ 2024-01-02 17:08     ` Ray Andrews
  2024-01-02 17:47       ` Mark J. Reed
  2024-01-02 17:48       ` Peter Stephenson
  0 siblings, 2 replies; 25+ messages in thread
From: Ray Andrews @ 2024-01-02 17:08 UTC (permalink / raw)
  To: zsh-users


On 2024-01-02 03:50, Peter Stephenson wrote:
>> On 30/12/2023 20:38 GMT Bart Schaefer <schaefer@brasslantern.com> wrote:
>> Arguably zmv could use null_glob.  Thoughts from -workers?
> I guess the right thing to do regardless of option is that it should
> fail gracefully just by returning status 1 --- so not propagating the
> error to the caller.

That's just was I was trying to say :-)

There's a lot to be said for graceful failure.  If one wishes to crash 
the calling function one should  of course have that option, but why 
make it the default?  There's a sorta 'invisible return' there and the 
'always' thing counteracts it, but it all seems so unnecessary.  No 
invisible code, please.

BTW, just to whine, 'always' is sure hard to find in the help. One 
obviously can't just search for that word, and it doesn't show up in the 
list of reserved words neither.








^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 17:08     ` Ray Andrews
@ 2024-01-02 17:47       ` Mark J. Reed
  2024-01-02 18:16         ` Ray Andrews
  2024-01-02 17:48       ` Peter Stephenson
  1 sibling, 1 reply; 25+ messages in thread
From: Mark J. Reed @ 2024-01-02 17:47 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 2690 bytes --]

On Tue, Jan 2, 2024 at 12:09 PM Ray Andrews <rayandrews@eastlink.ca> wrote:

> BTW, just to whine, 'always' is sure hard to find in the help. One
> obviously can't just search for that word, and it doesn't show up in the
> list of reserved words neither.
>

Shell Grammar, under Complex Commands. (A bit of jargon, really; a command
line to execute a program once is a "simple" command; anything that
combines simple commands together – a loop or conditional or whatever –is a
"complex" command):

https://zsh.sourceforge.io/Doc/Release/Shell-Grammar.html#Complex-Commands

> That's what I meant.  Right tho -- it's handled in two passes but one is
called  parsing, the second is called running.   But the parse sets a memo
that zmv will not be permitted to crash the function at run time.

Well, no.  It runs the code on the left, and then when it finishes it runs
the code on the right. That's the extent of the `always` functionality.
What makes it special is that the code on the right runs even if the code
on the left blows up somehow.

It's similar to a feature called the "finally block" in other languages,
where it's usually attached to the exception-handling mechanism; something
like `try { start here } catch (ErrorType) { do this if the previous block
failed this particular way } finally { run this no matter what }`.  Because
of that similarity, the code on the left of the `always` is called the "try
block" or "try list", even though zsh doesn't use the keyword "try". The
code on the right is called the "always block" or "always list".

So, the point of `always` is to run the always block no matter what, even
if the try block blows up. But now we have an information problem: the main
point of the exercise was to run the code in the try block, and presumably
the caller would like to know whether it blew up or not. But how does that
information get back to them? You can't just go by exit code
(`$?`/`$status`), because by the time control gets back to the caller, that
will reflect the result of the always block, not the try block.

Zsh uses a variable called TRY_BLOCK_ERROR (which should be read as "an
error that occurred in the 'try' block" rather than some version of "try to
block the error" :)) to remember whether the try block errored out or not.
If it did, that variable will be 1, and after the always block executes,
zsh will go back to handling the error (i.e. potentially blowing up the
world). If you want the world not to be blown up, you can set
TRY_BLOCK_ERROR to 0, and then zsh will forget that anything went wrong and
continue about its business.

-- 
Mark J. Reed <markjreed@gmail.com>

[-- Attachment #2: Type: text/html, Size: 3543 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 17:08     ` Ray Andrews
  2024-01-02 17:47       ` Mark J. Reed
@ 2024-01-02 17:48       ` Peter Stephenson
  2024-01-02 19:07         ` Bart Schaefer
  1 sibling, 1 reply; 25+ messages in thread
From: Peter Stephenson @ 2024-01-02 17:48 UTC (permalink / raw)
  To: zsh-users


> On 02/01/2024 17:08 GMT Ray Andrews <rayandrews@eastlink.ca> wrote:
> 
>  
> On 2024-01-02 03:50, Peter Stephenson wrote:
> >> On 30/12/2023 20:38 GMT Bart Schaefer <schaefer@brasslantern.com> wrote:
> >> Arguably zmv could use null_glob.  Thoughts from -workers?
> > I guess the right thing to do regardless of option is that it should
> > fail gracefully just by returning status 1 --- so not propagating the
> > error to the caller.
> 
> That's just was I was trying to say :-)

So how about this...

pws

diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index f43ac2257..182fc5f0a 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -4667,11 +4667,12 @@ renames `tt(foo.lis)' to `tt(foo.txt)', `tt(my.old.stuff.lis)' to
 `tt(my.old.stuff.txt)', and so on.
 
 The pattern is always treated as an tt(EXTENDED_GLOB) pattern.  Any file
-whose name is not changed by the substitution is simply ignored.  Any
-error (a substitution resulted in an empty string, two substitutions gave
-the same result, the destination was an existing regular file and tt(-f)
-was not given) causes the entire function to abort without doing
-anything.
+whose name is not changed by the substitution is simply ignored; if no
+files are matched by the pattern, the function silently returns status
+1.  Any error (a substitution resulted in an empty string, two
+substitutions gave the same result, the destination was an existing
+regular file and tt(-f) was not given) causes the entire function to
+abort without doing anything.
 
 In addition to pattern replacement, the variable tt($f) can be referred
 to in the second (replacement) argument.  This makes it possible to
diff --git a/Functions/Misc/zmv b/Functions/Misc/zmv
index 269fe5ba5..177428f08 100644
--- a/Functions/Misc/zmv
+++ b/Functions/Misc/zmv
@@ -236,7 +236,11 @@ if [[ $pat = (#b)(*)\((\*\*##/)\)(*) ]]; then
 else
   fpat=$pat
 fi
-files=(${~fpat})
+files=(${~fpat}(#qN))
+
+if (( ${#files} == 0 )); then
+  return 1
+fi
 
 [[ -n $hasglobqual ]] && pat=$opat


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 17:47       ` Mark J. Reed
@ 2024-01-02 18:16         ` Ray Andrews
  2024-01-02 20:24           ` Bart Schaefer
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-01-02 18:16 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1874 bytes --]


On 2024-01-02 09:47, Mark J. Reed wrote:
>
>
> https://zsh.sourceforge.io/Doc/Release/Shell-Grammar.html#Complex-Commands
>
Thanks.  Man, I wish there were more examples :(


> Well, no.  It runs the code on the left, and then when it finishes it 
> runs the code on the right. That's the extent of the `always` 
> functionality. What makes it special is that the code on the right 
> runs even if the code on the left blows up somehow.
Yeah, I think I get it.  But the 'memo' has to be there -- zmv must ... 
or maybe not ... when zmv returns, if the 'always' keyword (sorta) it 
there, then it knows to not crash but to execute the following code.  
So, yeah, it could be seen as 'linear'.
>
> It's similar to a feature called the "finally block" in other 
> languages, where it's usually attached to the exception-handling 
> mechanism; something like `try { start here } catch (ErrorType) { do 
> this if the previous block failed this particular way } finally { run 
> this no matter what }`.  Because of that similarity, the code on the 
> left of the `always` is called the "try block" or "try list", even 
> though zsh doesn't use the keyword "try". The code on the right is 
> called the "always block" or "always list".
That's interesting.  So this isn't some desperate hack -- that kind of 
functionality is standard to some degree.  Ok, good to know. But as I 
said, it sure looks strange the first time you see it.  Reading a bit 
more, I see it's got other uses than preventing meltdowns. Cool.
>
> If you want the world not to be blown up, you can set TRY_BLOCK_ERROR 
> to 0, and then zsh will forget that anything went wrong and continue 
> about its business.

I myself hardly ever want Ragnarok, so next time I run into this sort of 
issue, I've got that to defuse it.  Thanks Mark.  Hey, I wonder if that 
could be an option? NO_MELTDOWNS=on


[-- Attachment #2: Type: text/html, Size: 3607 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 17:48       ` Peter Stephenson
@ 2024-01-02 19:07         ` Bart Schaefer
  2024-01-02 19:52           ` Ray Andrews
  2024-01-03  9:55           ` Peter Stephenson
  0 siblings, 2 replies; 25+ messages in thread
From: Bart Schaefer @ 2024-01-02 19:07 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-users

On Tue, Jan 2, 2024 at 9:48 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> So how about this...

That's what my patch in users/29387 does, except mine emits an error
message similar to all the other zmv error messages for pattern
failures, rather than silently returning 1.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 19:07         ` Bart Schaefer
@ 2024-01-02 19:52           ` Ray Andrews
  2024-01-03  9:55           ` Peter Stephenson
  1 sibling, 0 replies; 25+ messages in thread
From: Ray Andrews @ 2024-01-02 19:52 UTC (permalink / raw)
  To: zsh-users


On 2024-01-02 11:07, Bart Schaefer wrote:
> On Tue, Jan 2, 2024 at 9:48 AM Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
>> So how about this...
> That's what my patch in users/29387 does, except mine emits an error
> message similar to all the other zmv error messages for pattern
> failures, rather than silently returning 1.
Messages are always friendly especially since one can redirect them to 
null if one doesn't want to see them.  Or just have a 'silent' 
option/switch.
>


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 18:16         ` Ray Andrews
@ 2024-01-02 20:24           ` Bart Schaefer
  2024-01-02 21:32             ` Ray Andrews
  0 siblings, 1 reply; 25+ messages in thread
From: Bart Schaefer @ 2024-01-02 20:24 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

On Tue, Jan 2, 2024 at 10:16 AM Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> Yeah, I think I get it.  But the 'memo' has to be there -- zmv must ... or maybe not ... when zmv returns, if the 'always' keyword (sorta) it there, then it knows to not crash but to execute the following code.  So, yeah, it could be seen as 'linear'.

To avoid giving other readers a wrong conclusion ...

There are a number of failure cases defined by e.g. the POSIX
specification, or in some cases by longstanding zsh practice, that are
considered fatal errors.  When one of those errors is encountered,
whatever it is that the shell is doing, simply stops.  In a script,
this exits the entire script; in an interactive shell, it returns to
the top-level prompt.  In this specific example, there is no "zmv
returns":  it ends, full stop, no return value, nothing back to the
caller.  This is not a "crash", it's a well-defined exit condition.
(Whether it SHOULD be that condition specifically in zmv, is the topic
elsewhere in this thread.)  For a C equivalence, it's similar to
abort() having been called.

The "always" construct does nothing to the behavior of e.g. zmv, and
does not "memo" anything.  It allows calling code to intercept the
well-defined exit state and clean up.  (A "crash" would be an
unrecoverable condition in which not even "always" would be possible.)
 If the calling code does not intercept the exit state, then the
calling code also stops, and so on up the chain until (in an
interactive shell) the top-level interpreter implicitly sets a
non-zero status and prompts again.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 20:24           ` Bart Schaefer
@ 2024-01-02 21:32             ` Ray Andrews
  0 siblings, 0 replies; 25+ messages in thread
From: Ray Andrews @ 2024-01-02 21:32 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1133 bytes --]


On 2024-01-02 12:24, Bart Schaefer wrote:
> When one of those errors is encountered,
> whatever it is that the shell is doing, simply stops.  In a script,
> this exits the entire script; in an interactive shell, it returns to
> the top-level prompt.  In this specific example, there is no "zmv
> returns":  it ends, full stop, no return value, nothing back to the
> caller.

That's clear, but I had no idea that was the case.  Nothing back?  
Sounds inadvisable  but ...

>    This is not a "crash", it's a well-defined exit condition.
Right, I'm corrected.  Yes, 'crash' is a sloppy choice of words. I don't 
doubt zsh 'knows what it's doing' but it has the look of what Elon calls 
a rapid unscheduled disassembly.
> The "always" construct does nothing to the behavior of e.g. zmv, and
> does not "memo" anything.  It allows calling code to intercept the
> well-defined exit state and clean up.

I think I'd have to see the actual nuts and bolts of it to really 
understand.  It's not important.  I learned quite a bit.

Oh, when the devs have a final cut of the new zmv, if it's posted, I'll 
paste it over my copy here.



[-- Attachment #2: Type: text/html, Size: 2052 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-02 19:07         ` Bart Schaefer
  2024-01-02 19:52           ` Ray Andrews
@ 2024-01-03  9:55           ` Peter Stephenson
  2024-01-03 15:46             ` Ray Andrews
  1 sibling, 1 reply; 25+ messages in thread
From: Peter Stephenson @ 2024-01-03  9:55 UTC (permalink / raw)
  To: zsh-users


> On 02/01/2024 19:07 GMT Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Tue, Jan 2, 2024 at 9:48 AM Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
> >
> > So how about this...
> 
> That's what my patch in users/29387 does, except mine emits an error
> message similar to all the other zmv error messages for pattern
> failures, rather than silently returning 1.

Sounds like that ought to be fine.

pws


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-03  9:55           ` Peter Stephenson
@ 2024-01-03 15:46             ` Ray Andrews
  2024-01-03 19:01               ` Bart Schaefer
  0 siblings, 1 reply; 25+ messages in thread
From: Ray Andrews @ 2024-01-03 15:46 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 111 bytes --]


On 2024-01-03 01:55, Peter Stephenson wrote:
> Sounds like that ought to be fine.
May I have a copy gentlemen?

[-- Attachment #2: Type: text/html, Size: 551 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: zmv exits from function
  2024-01-03 15:46             ` Ray Andrews
@ 2024-01-03 19:01               ` Bart Schaefer
  0 siblings, 0 replies; 25+ messages in thread
From: Bart Schaefer @ 2024-01-03 19:01 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

[-- Attachment #1: Type: text/plain, Size: 97 bytes --]

Updated patch including doc edit will be sent to zsh-workers.  Here's
a copy of the edited file.

[-- Attachment #2: zmv --]
[-- Type: application/octet-stream, Size: 11545 bytes --]

# function zmv {
# zmv, zcp, zln:
#
# This is a multiple move based on zsh pattern matching.  To get the full
# power of it, you need a postgraduate degree in zsh.  However, simple
# tasks work OK, so if that's all you need, here are some basic examples:
#   zmv '(*).txt' '$1.lis'
# Rename foo.txt to foo.lis, etc.  The parenthesis is the thing that
# gets replaced by the $1 (not the `*', as happens in mmv, and note the
# `$', not `=', so that you need to quote both words).
#   zmv '(**/)(*).txt '$1$2.lis'
# The same, but scanning through subdirectories.  The $1 becomes the full
# path.  Note that you need to write it like this; you can't get away with
# '(**/*).txt'.
#   zmv -w '**/*.txt' '$1$2.lis'
#   noglob zmv -W **/*.txt **/*.lis
# These are the lazy version of the one above; with -w, zsh inserts the
# parentheses for you in the search pattern, and with -W it also inserts
# the numbered variables for you in the replacement pattern.  The catch
# in the first version is that you don't need the / in the replacement
# pattern.  (It's not really a catch, since $1 can be empty.)  Note that
# -W actually inserts ${1}, ${2}, etc., so it works even if you put a
# number after a wildcard (such as zmv -W '*1.txt' '*2.txt').
#   zmv -C '**/(*).txt' ~/save/'$1'.lis
# Copy, instead of move, all .txt files in subdirectories to .lis files
# in the single directory `~/save'.  Note that the ~ was not quoted.
# You can test things safely by using the `-n' (no, not now) option.
# Clashes, where multiple files are renamed or copied to the same one, are
# picked up.
#
# Here's a more detailed description.
#
# Use zsh pattern matching to move, copy or link files, depending on
# the last two characters of the function name.  The general syntax is
#   zmv '<inpat>' '<outstring>'
# <inpat> is a globbing pattern, so it should be quoted to prevent it from
# immediate expansion, while <outstring> is a string that will be
# re-evaluated and hence may contain parameter substitutions, which should
# also be quoted.  Each set of parentheses in <inpat> (apart from those
# around glob qualifiers, if you use the -Q option, and globbing flags) may
# be referred to by a positional parameter in <outstring>, i.e. the first
# (...) matched is given by $1, and so on.  For example,
#   zmv '([a-z])(*).txt' '${(C)1}$2.txt'
# renames algernon.txt to Algernon.txt, boris.txt to Boris.txt and so on.
# The original file matched can be referred to as $f in the second
# argument; accidental or deliberate use of other parameters is at owner's
# risk and is not covered by the (non-existent) guarantee.
#
# As usual in zsh, /'s don't work inside parentheses.  There is a special
# case for (**/) and (***/):  these have the expected effect that the
# entire relevant path will be substituted by the appropriate positional
# parameter.
#
# There is a shortcut avoiding the use of parenthesis with the option -w
# (with wildcards), which picks out any expressions `*', `?', `<range>'
# (<->, <1-10>, etc.), `[...]', possibly followed by `#'s, `**/', `***/', and
# automatically parenthesises them. (You should quote any ['s or ]'s which
# appear inside [...] and which do not come from ranges of the form
# `[:alpha:]'.)  So for example, in
#    zmv -w '[[:upper:]]*' '${(L)1}$2'
# the $1 refers to the expression `[[:upper:]]' and the $2 refers to
# `*'. Thus this finds any file with an upper case first character and
# renames it to one with a lowercase first character.  Note that any
# existing parentheses are active, too, so you must count accordingly.
# Furthermore, an expression like '(?)' will be rewritten as '((?))' --- in
# other words, parenthesising of wildcards is independent of any existing
# parentheses.
#
# Any file whose name is not changed by the substitution is simply ignored.
# Any error --- a substitution resulted in an empty string, two
# substitutions gave the same result, the destination was an existing
# regular file and -f was not given --- causes the entire function to abort
# without doing anything.
#
# Options:
#  -f  force overwriting of destination files.  Not currently passed
#      down to the mv/cp/ln command due to vagaries of implementations
#      (but you can use -o-f to do that).
#  -i  interactive: show each line to be executed and ask the user whether
#      to execute it.  Y or y will execute it, anything else will skip it.
#      Note that you just need to type one character.
#  -n  no execution: print what would happen, but don't do it.
#  -q  Turn bare glob qualifiers off:  now assumed by default, so this
#      has no effect.
#  -Q  Force bare glob qualifiers on.  Don't turn this on unless you are
#      actually using glob qualifiers in a pattern (see below).
#  -s  symbolic, passed down to ln; only works with zln or z?? -L.
#  -v  verbose: print line as it's being executed.
#  -o <optstring>
#      <optstring> will be split into words and passed down verbatim
#      to the cp, ln or mv called to perform the work.  It will probably
#      begin with a `-'.
#  -p <program>
#      Call <program> instead of cp, ln or mv.  Whatever it does, it should
#      at least understand the form '<program> -- <oldname> <newname>',
#      where <oldname> and <newname> are filenames generated. <program>
#      will be split into words.
#  -P <program>
#      As -p, but the program doesn't understand the "--" convention.
#      In this case the file names must already be sane.
#  -w  Pick out wildcard parts of the pattern, as described above, and
#      implicitly add parentheses for referring to them.
#  -W  Just like -w, with the addition of turning wildcards in the
#      replacement pattern into sequential ${1} .. ${N} references.
#  -C
#  -L
#  -M  Force cp, ln or mv, respectively, regardless of the name of the
#      function.
#
# Bugs:
#   Parenthesised expressions can be confused with glob qualifiers, for
#   example a trailing '(*)' would be treated as a glob qualifier in
#   ordinary globbing.  This has proved so annoying that glob qualifiers
#   are now turned off by default.  To force the use of glob qualifiers,
#   give the flag -Q.
#
#   The pattern is always treated as an extendedglob pattern.  This
#   can also be interpreted as a feature.
#
# Unbugs:
#   You don't need braces around the 1 in expressions like '$1t' as
#   non-positional parameters may not start with a number, although
#   paranoiacs like the author will probably put them there anyway.

emulate -RL zsh
setopt extendedglob

local f g args match mbegin mend files action myname tmpf opt exec
local opt_f opt_i opt_n opt_q opt_Q opt_s opt_M opt_C opt_L 
local opt_o opt_p opt_P opt_v opt_w opt_W MATCH MBEGIN MEND
local pat repl errstr fpat hasglobqual opat
typeset -A from to
integer stat

local dashes=--

myname=${(%):-%N}

while getopts ":o:p:P:MCLfinqQsvwW" opt; do
  if [[ $opt = "?" ]]; then
    print -r -- "$myname: unrecognized option: -$OPTARG" >&2
    return 1
  fi
  eval "opt_$opt=\${OPTARG:--\$opt}"
done
(( OPTIND > 1 )) && shift $(( OPTIND - 1 ))

[[ -z $opt_Q ]] && setopt nobareglobqual
[[ -n $opt_M ]] && action=mv
[[ -n $opt_C ]] && action=cp
[[ -n $opt_L ]] && action=ln
[[ -n $opt_p ]] && action=$opt_p
[[ -n $opt_P ]] && action=$opt_P dashes=

if [[ -z $action ]]; then
  action=$myname[-2,-1]

  if [[ $action != (cp|mv|ln) ]]; then
    print -r "$myname: action $action not recognised: must be cp, mv or ln." >&2
    return 1
  fi
fi

if (( $# != 2 )); then
  print -P "Usage:
  %N [OPTIONS] oldpattern newpattern
where oldpattern contains parenthesis surrounding patterns which will
be replaced in turn by \$1, \$2, ... in newpattern.  For example,
  %N '(*).lis' '\$1.txt'
renames 'foo.lis' to 'foo.txt', 'my.old.stuff.lis' to 'my.old.stuff.txt',
and so on.  Something simpler (for basic commands) is the -W option:
  %N -W '*.lis' '*.txt'
This does the same thing as the first command, but with automatic conversion
of the wildcards into the appropriate syntax.  If you combine this with
noglob, you don't even need to quote the arguments.  For example,
  alias mmv='noglob zmv -W'
  mmv *.c.orig orig/*.c" >&2
  return 1
fi

pat=$1
repl=$2
shift 2

if [[ -n $opt_s && $action != ln ]]; then
  print -r -- "$myname: invalid option: -s" >&2
  return 1
fi

if [[ -n $opt_w || -n $opt_W ]]; then
  # Parenthesise all wildcards.
  local tmp find
  integer cnt=0
  # Well, this seems to work.
  # The tricky bit is getting all forms of [...] correct, but as long
  # as we require inactive bits to be backslashed its not so bad.
  find='(#m)((\*\*##/|[*?]|<[0-9]#-[0-9]#>|\[(^|)(\]|)(\[:[a-z]##:\]|\\?|[^\]])##\])\##|?\###)'
  tmp="${pat//${~find}/$[++cnt]}"
  if [[ $cnt = 0 ]]; then
    print -r -- "$myname: warning: no wildcards were found in search pattern" >&2
  else
    pat="${pat//${~find}/($MATCH)}"
  fi
  if [[ -n $opt_W ]]; then
    # Turn wildcards into ${1} .. ${N} references.
    local open='${' close='}'
    integer N=0
    repl="${repl//${~find}/$open$[++N]$close}"
    if [[ $N != $cnt ]]; then
      print -P "%N: error: number of wildcards in each pattern must match" >&2
      return 1
    fi
    if [[ $N = 0 ]]; then
      print -P "%N: warning: no wildcards were found in replacement pattern" >&2
    fi
  fi
fi

if [[ -n $opt_Q && $pat = (#b)(*)\([^\)\|\~]##\) ]]; then
  hasglobqual=q
  # strip off qualifiers for use as ordinary pattern
  opat=$match[1]
fi

if [[ $pat = (#b)(*)\((\*\*##/)\)(*) ]]; then
  fpat="$match[1]$match[2]$match[3]"
  # Now make sure we do depth-first searching.
  # This is so that the names of any files are altered before the
  # names of the directories they are in.
  if [[ -n $opt_Q && -n $hasglobqual ]]; then
    fpat[-1]="odon)"
  else
    setopt bareglobqual
    fpat="${fpat}(odon)"
  fi
else
  fpat=$pat
fi

[[ -n $hasglobqual ]] && pat=$opat

errs=()

() {
  # (#qN) breaks bareglobqual -Q option, so:
  setopt localoptions nullglob
  files=(${~fpat})
}
(( ${#files} )) || errs=( "no files matched \`$fpat'" )

for f in $files; do
  if [[ $pat = (#b)(*)\(\*\*##/\)(*) ]]; then
    # This looks like a recursive glob.  This isn't good enough,
    # because we should really enforce that $match[1] and $match[2]
    # don't match slashes unless they were explicitly given.  But
    # it's a start.  It's fine for the classic case where (**/) is
    # at the start of the pattern.
    pat="$match[1](*/|)$match[2]"
  fi
  [[ -e $f && $f = (#b)${~pat} ]] || continue
  set -- "$match[@]"
  { {
    g=${(Xe)repl}
  } 2> /dev/null } always {
    if (( TRY_BLOCK_ERROR )); then
      print -r -- "$myname: syntax error in replacement" >&2
      return 1
    fi
  }
  if [[ -z $g ]]; then
    errs+=("\`$f' expanded to an empty string")
  elif [[ $f = $g ]]; then
    # don't cause error: more useful just to skip
    #   errs=($errs "$f not altered by substitution")
    [[ -n $opt_v ]] && print -r -- "$f not altered, ignored"
    continue
  elif [[ -n $from[$g] && ! -d $g ]]; then
    errs+=("$f and $from[$g] both map to $g")
  elif [[ -f $g && -z $opt_f && ! ($f -ef $g && $action = mv) ]]; then
    errs+=("file exists: $g")
  fi
  from[$g]=$f
  to[$f]=$g
done

if (( $#errs )); then
  print -r -- "$myname: error(s) in substitution:" >&2
  print -lr -- $errs >&2
  return 1
fi

for f in $files; do
  [[ -z $to[$f] ]] && continue
  exec=(${=action} ${=opt_o} $opt_s $dashes $f $to[$f])
  [[ -n $opt_i$opt_n$opt_v ]] && print -r -- ${(q-)exec}
  if [[ -n $opt_i ]]; then
    read -q 'opt?Execute? ' || continue
  fi
  if [[ -z $opt_n ]]; then
    $exec || stat=1
  fi
done

return $stat
# }

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2024-01-03 19:02 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-30 17:42 zmv exits from function Ray Andrews
2023-12-30 20:38 ` Bart Schaefer
2023-12-30 21:02   ` Ray Andrews
2023-12-30 22:21     ` Bart Schaefer
2023-12-30 21:15   ` Mikael Magnusson
2023-12-31  3:43     ` Ray Andrews
2023-12-31  3:58       ` Bart Schaefer
2023-12-31 15:53         ` Ray Andrews
2023-12-31 21:44           ` Bart Schaefer
2023-12-31 22:06             ` Ray Andrews
2024-01-02 14:51               ` Mark J. Reed
2024-01-02 17:01                 ` Ray Andrews
2024-01-02 11:50   ` Peter Stephenson
2024-01-02 17:08     ` Ray Andrews
2024-01-02 17:47       ` Mark J. Reed
2024-01-02 18:16         ` Ray Andrews
2024-01-02 20:24           ` Bart Schaefer
2024-01-02 21:32             ` Ray Andrews
2024-01-02 17:48       ` Peter Stephenson
2024-01-02 19:07         ` Bart Schaefer
2024-01-02 19:52           ` Ray Andrews
2024-01-03  9:55           ` Peter Stephenson
2024-01-03 15:46             ` Ray Andrews
2024-01-03 19:01               ` Bart Schaefer
2023-12-30 22:34 ` Bart Schaefer

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).