zsh-workers
 help / color / mirror / code / Atom feed
* Potential improvement for zmv
@ 2002-03-28  0:48 Wayne Davison
  2002-03-28 15:59 ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: Wayne Davison @ 2002-03-28  0:48 UTC (permalink / raw)
  To: Zsh Workers

I implemented a new option for zmv: -W.  This works just like -w, with
the additional feature that it automatically transforms wildcards in the
replacement pattern into a sequential series of ${1} .. ${N} vars.  This
allows you to do things like this:

  alias mmv='noglob zmv -W'
  mmv *.orig orig/*
  mmv **/*.txt **/*.lis

Since I'm still a novice shell programmer, some of you wizards out
there can undoubtedly improve the shell code I wrote.  For instance,
I don't know if it's possible to increment $N inside a global search
and replace (I resorted to using a loop).

Here's the patch.  Let me know what you think.

..wayne..

---8<------8<------8<------8<---cut here--->8------>8------>8------>8---
Index: zsh/Functions/Misc/zmv
--- zsh/Functions/Misc/zmv	28 Aug 2001 20:28:18 -0000	1.9
+++ zsh/Functions/Misc/zmv	28 Mar 2002 00:45:34 -0000
@@ -13,9 +13,14 @@
 # path.  Note that you need to write it like this; you can't get away with
 # '(**/*).txt'.
 #   zmv -w '**/*.txt' '$1$2.lis'
-# This is the lazy version of the one above; zsh picks out the patterns
-# for you.  The catch here is that you don't need the / in the replacement
-# pattern.  (It's not really a catch, since $1 can be empty.)
+#   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 actuall 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.
@@ -91,6 +96,8 @@
 #      where <oldname> and <newname> are filenames generated.
 #  -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
@@ -116,12 +123,12 @@

 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_v opt_w MATCH MBEGIN MEND
+local opt_o opt_p opt_v opt_w opt_W MATCH MBEGIN MEND
 local pat repl errstr fpat hasglobqual opat
 typeset -A from to
 integer stat

-while getopts ":o:p:MCLfinqQsvw" opt; do
+while getopts ":o:p:MCLfinqQsvwW" opt; do
   if [[ $opt = "?" ]]; then
     print -P "%N: unrecognized option: -$OPTARG" >&2
     return 1
@@ -173,7 +180,7 @@
   return 1
 fi

-if [[ -n $opt_w ]]; then
+if [[ -n $opt_w || -n $opt_W ]]; then
   # Parenthesise all wildcards.
   local newpat
   # Well, this seems to work.
@@ -183,9 +190,27 @@
 (#m)(\*\*#\/|[*?]|\<[0-9]#-[0-9]#\>|\[(\[:[a-z]##:\]|\\\[|\\\]|[^\[\]]##)##\])\##\
 /($MATCH)}"
   if [[ $newpat = $pat ]]; then
-    print -P "%N: warning: no wildcards were found" >&2
+    print -P "%N: warning: no wildcards were found in search pattern" >&2
   else
     pat=$newpat
+  fi
+  if [[ -n $opt_W ]]; then
+    # Turn wildcards into ${1} .. ${N} references.
+    local N=1
+    local tmp=X
+    newpat=$repl
+    while [[ $newpat != $tmp ]]; do
+      tmp=$newpat
+      newpat="${newpat/\
+(#m)(\*\*#\/|[*?]|\<[0-9]#-[0-9]#\>|\[(\[:[a-z]##:\]|\\\[|\\\]|[^\[\]]##)##\])\##\
+/\${$N\}}"
+      (( N++ ))
+    done
+    if [[ $newpat = $repl ]]; then
+      print -P "%N: warning: no wildcards were found in replacement pattern" >&2
+    else
+      repl=$newpat
+    fi
   fi
 fi

---8<------8<------8<------8<---cut here--->8------>8------>8------>8---


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

* Re: Potential improvement for zmv
  2002-03-28  0:48 Potential improvement for zmv Wayne Davison
@ 2002-03-28 15:59 ` Bart Schaefer
  2002-03-29  1:12   ` PATCH: -W option for zmv (updated) Wayne Davison
  0 siblings, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2002-03-28 15:59 UTC (permalink / raw)
  To: Zsh Workers

On Mar 27,  4:48pm, Wayne Davison wrote:
} Subject: Potential improvement for zmv
}
} I implemented a new option for zmv: -W.  This works just like -w, with
} the additional feature that it automatically transforms wildcards in the
} replacement pattern into a sequential series of ${1} .. ${N} vars.
} 
} Here's the patch.  Let me know what you think.

My only concern is that it should complain if the number of wildcards in
the destination is less than the number of wildcards in the source.  Else
you're likely to lose the rightmost patterns from the source, which are
probably the most important (the file name itself).

} Since I'm still a novice shell programmer, some of you wizards out
} there can undoubtedly improve the shell code I wrote.  For instance,
} I don't know if it's possible to increment $N inside a global search
} and replace (I resorted to using a loop).

You can just about do it:

integer N=0
x=(x x x x x x)
print ${(e)x//x/\$[++N]}

but the escaping to wrap each $[++N] in ${...} gets a bit arcane.

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


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

* PATCH: -W option for zmv (updated)
  2002-03-28 15:59 ` Bart Schaefer
@ 2002-03-29  1:12   ` Wayne Davison
  2002-03-29  2:38     ` Bart Schaefer
  0 siblings, 1 reply; 5+ messages in thread
From: Wayne Davison @ 2002-03-29  1:12 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Workers

On Thu, 28 Mar 2002, Bart Schaefer wrote:
> My only concern is that it should complain if the number of wildcards in
> the destination is less than the number of wildcards in the source.

Good point.  I've made it complain and exit if the counts don't match.

> integer N=0
> x=(x x x x x x)
> print ${(e)x//x/\$[++N]}

Thanks!  That's the nudge I needed to make things more efficient.

The only weird thing I ran into was when I put the find pattern into a
variable so I could reuse it in 3 spots.  To get things working I had to
change the "\/" into "[/]" or the "\*\*#\/" pattern wouldn't match.
Strange.

Here's my latest patch.  I'll probably commit this after a little more
testing (unless someone has an objection).

..wayne..

---8<------8<------8<------8<---cut here--->8------>8------>8------>8---
Index: zsh/Functions/Misc/zmv
--- zsh/Functions/Misc/zmv	28 Aug 2001 20:28:18 -0000	1.9
+++ zsh/Functions/Misc/zmv	29 Mar 2002 01:04:32 -0000
@@ -13,9 +13,14 @@
 # path.  Note that you need to write it like this; you can't get away with
 # '(**/*).txt'.
 #   zmv -w '**/*.txt' '$1$2.lis'
-# This is the lazy version of the one above; zsh picks out the patterns
-# for you.  The catch here is that you don't need the / in the replacement
-# pattern.  (It's not really a catch, since $1 can be empty.)
+#   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.
@@ -91,6 +96,8 @@
 #      where <oldname> and <newname> are filenames generated.
 #  -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
@@ -116,12 +123,12 @@

 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_v opt_w MATCH MBEGIN MEND
+local opt_o opt_p opt_v opt_w opt_W MATCH MBEGIN MEND
 local pat repl errstr fpat hasglobqual opat
 typeset -A from to
 integer stat

-while getopts ":o:p:MCLfinqQsvw" opt; do
+while getopts ":o:p:MCLfinqQsvwW" opt; do
   if [[ $opt = "?" ]]; then
     print -P "%N: unrecognized option: -$OPTARG" >&2
     return 1
@@ -173,19 +180,32 @@
   return 1
 fi

-if [[ -n $opt_w ]]; then
+if [[ -n $opt_w || -n $opt_W ]]; then
   # Parenthesise all wildcards.
-  local newpat
+  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.
-  newpat="${pat//\
-(#m)(\*\*#\/|[*?]|\<[0-9]#-[0-9]#\>|\[(\[:[a-z]##:\]|\\\[|\\\]|[^\[\]]##)##\])\##\
-/($MATCH)}"
-  if [[ $newpat = $pat ]]; then
-    print -P "%N: warning: no wildcards were found" >&2
+  find='(#m)(\*\*#[/]|[*?]|\<[0-9]#-[0-9]#\>|\[(\[:[a-z]##:\]|\\\[|\\\]|[^\[\]]##)##\])\##'
+  tmp="${pat//${~find}/$[++cnt]}"
+  if [[ $cnt = 0 ]]; then
+    print -P "%N: warning: no wildcards were found in search pattern" >&2
   else
-    pat=$newpat
+    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

---8<------8<------8<------8<---cut here--->8------>8------>8------>8---


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

* Re: PATCH: -W option for zmv (updated)
  2002-03-29  1:12   ` PATCH: -W option for zmv (updated) Wayne Davison
@ 2002-03-29  2:38     ` Bart Schaefer
  2002-03-29  5:32       ` Wayne Davison
  0 siblings, 1 reply; 5+ messages in thread
From: Bart Schaefer @ 2002-03-29  2:38 UTC (permalink / raw)
  To: zsh-workers

On Mar 28,  5:12pm, Wayne Davison wrote:

> > x=(x x x x x x)
> > print ${(e)x//x/\$[++N]}
> 
> Thanks!  That's the nudge I needed to make things more efficient.
> 
> +  find='(#m)(\*\*#[/]|[*?]|\<[0-9]#-[0-9]#\>|\[(\[:[a-z]##:\]|\\\[|\\\]|[^\[\]]##)##\])\##'
> +  tmp="${pat//${~find}/$[++cnt]}"

and later

> +    integer N=0
> +    repl="${repl//${~find}/$open$[++N]$close}"

That doesn't work for me:

schaefer[501] find=x open=\$\{ close=\}
schaefer[502] repl=xxxxxx
schaefer[503] N=0
schaefer[504] repl="${repl//${~find}/$open$[++N]$close}"
schaefer[505] echo $repl
${1}${1}${1}${1}${1}${1}

It should be

repl="${(e)repl//${~find}/\$open\$[++N]\$close}"

Are you sure you sent the correct version of the patch?


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

* Re: PATCH: -W option for zmv (updated)
  2002-03-29  2:38     ` Bart Schaefer
@ 2002-03-29  5:32       ` Wayne Davison
  0 siblings, 0 replies; 5+ messages in thread
From: Wayne Davison @ 2002-03-29  5:32 UTC (permalink / raw)
  To: Zsh Workers

On Thu, 28 Mar 2002, Bart Schaefer wrote:
> repl="${(e)repl//${~find}/\$open\$[++N]\$close}"

I confirmed with Bart that he had simplified his test case a little too
far.  This extra evaluation is not needed in zmv because the $find var
is using (#m), and thus the substitution side is already getting
evaluated multiple times (to support $MATCH).

..wayne..


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

end of thread, other threads:[~2002-03-29  5:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-03-28  0:48 Potential improvement for zmv Wayne Davison
2002-03-28 15:59 ` Bart Schaefer
2002-03-29  1:12   ` PATCH: -W option for zmv (updated) Wayne Davison
2002-03-29  2:38     ` Bart Schaefer
2002-03-29  5:32       ` Wayne Davison

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