From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 14320 invoked from network); 28 Mar 2002 00:48:49 -0000 Received: from sunsite.dk (130.225.247.90) by ns1.primenet.com.au with SMTP; 28 Mar 2002 00:48:49 -0000 Received: (qmail 6919 invoked by alias); 28 Mar 2002 00:48:39 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 16919 Received: (qmail 6905 invoked from network); 28 Mar 2002 00:48:37 -0000 Date: Wed, 27 Mar 2002 16:48:08 -0800 (PST) From: Wayne Davison X-X-Sender: To: Zsh Workers Subject: Potential improvement for zmv Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII 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 and 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---