* more fun with parameter expansion @ 2000-06-16 18:53 Clint Adams 2000-06-16 19:54 ` Clint Adams ` (2 more replies) 0 siblings, 3 replies; 8+ messages in thread From: Clint Adams @ 2000-06-16 18:53 UTC (permalink / raw) To: zsh-users This is for someone who wants to take a directory tree and convert all the filenames (and directory names) to lowercase, replacing spaces with underscores. It presumes that you are using GNU mv and have MARK_DIRS set. I'm sure that someone can make it more efficient. for i (*(/N)) {mv -v "$i" "${(L)i:gs/ /_/}"} for i (*/**/*(/N)) {mv -v "${${(L)i%/*/}:gs/ /_/}/${${${i#*/}%/}##*/}" "${(L)i:gfor i (**/*(N^/)) {mv -v "${i}" "${(L)i:gs/ /_/}"} ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-16 18:53 more fun with parameter expansion Clint Adams @ 2000-06-16 19:54 ` Clint Adams 2000-06-16 21:00 ` Bart Schaefer 2000-06-18 22:02 ` Peter Stephenson 2 siblings, 0 replies; 8+ messages in thread From: Clint Adams @ 2000-06-16 19:54 UTC (permalink / raw) To: zsh-users > for i (*(/N)) {mv -v "$i" "${(L)i:gs/ /_/}"} > for i (*/**/*(/N)) {mv -v "${${(L)i%/*/}:gs/ /_/}/${${${i#*/}%/}##*/}" "${(L)i:gfor i (**/*(N^/)) {mv -v "${i}" "${(L)i:gs/ /_/}"} > Hmm... I'll space them this time. for i (*(/N)) {mv -v "$i" "${(L)i:gs/ /_/}"} for i (*/**/*(/N)) {mv -v "${${(L)i%/*/}:gs/ /_/}/${${${i#*/}%/}##*/}" "${(L)i:gs/ /_/}"} for i (**/*(N^/)) {mv -v "${i}" "${(L)i:gs/ /_/}"} ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-16 18:53 more fun with parameter expansion Clint Adams 2000-06-16 19:54 ` Clint Adams @ 2000-06-16 21:00 ` Bart Schaefer 2000-06-16 21:44 ` Bart Schaefer 2000-06-18 22:02 ` Peter Stephenson 2 siblings, 1 reply; 8+ messages in thread From: Bart Schaefer @ 2000-06-16 21:00 UTC (permalink / raw) To: Clint Adams, zsh-users On Jun 16, 2:53pm, Clint Adams wrote: > Subject: more fun with parameter expansion > This is for someone who wants to take a directory tree and convert all > the filenames (and directory names) to lowercase, replacing spaces > with underscores. It presumes that you are using GNU mv and have > MARK_DIRS set. I'm sure that someone can make it more efficient. I dunno about efficient, but you can do it with only one glob and one loop, and it doesn't need to care about MARK_DIRS. Oh, and your solution missed file names that began with a dot, unless you meant to say that both MARK_DIRS and GLOB_DOTS were needed ... for f in **/*(DNon); do mv -v $f ${${(M)f%/*}:+${${f%/*}:l:gs/ /_/}}${${${(M)f%/*}:-$f}:l:gs/ /_/} done The `(on)' (order by name) is probably unnecessary, and won't work in 3.0.x (though everything else should). Writing that one-liner out a bit longer might make this more readable: t=${(M)f%/*} # The tail of the path, including leading slash h=${t:+${f%/*}} # The head of the path if the tail is non-empty t=${t:-$f} # The tail is the path when the tail is empty h=$h:l # Downcase the head, same as ${(L)h} t=$t:l # Downcase the tail h=$h:gs/ /_/ t=$h:gs/ /_/ mv $f $h$t The last five steps could be written as mv $f ${${:-$h$t}:l:gs/ /_/} Do you see what that's doing? Exercise: Rewrite the "mv" in my for-loop with that trick, to make it at least 8 characters shorter. Incidentally, you can turn on MARK_DIRS for individual globs like this: echo *(M) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-16 21:00 ` Bart Schaefer @ 2000-06-16 21:44 ` Bart Schaefer 2000-06-17 1:17 ` Clint Adams 0 siblings, 1 reply; 8+ messages in thread From: Bart Schaefer @ 2000-06-16 21:44 UTC (permalink / raw) To: Clint Adams, zsh-users On Jun 16, 2:00pm, Bart Schaefer wrote: > Subject: Re: more fun with parameter expansion > > for f in **/*(DNon); do > mv -v $f ${${(M)f%/*}:+${${f%/*}:l:gs/ /_/}}${${${(M)f%/*}:-$f}:l:gs/ /_/} > done > > The `(on)' (order by name) is probably unnecessary, and won't work in 3.0.x > (though everything else should). Of course I completely forgot that the whole reason I split the thing into head and tail was because this needs to work in REVERSE name order. Sigh. The correct solution is for f in **/*(DNOn^M); do mv -v $i ${${(M)i%/*}:+${i%/*}}${${${(M)i%/*}:-$i}:l:gs/ /_/} done (note one fewer :l:gs and turn *off* markdirs) which *won't* work in 3.0.x because of no (On) glob flag. > Writing that one-liner out a bit longer might make this more readable: > > t=${(M)f%/*} # The tail of the path, including leading slash > h=${t:+${f%/*}} # The head of the path if the tail is non-empty > t=${t:-$f} # The tail is the path when the tail is empty > > h=$h:l # Downcase the head, same as ${(L)h} > h=$h:gs/ /_/ This was my error; don't modify the head, instead wait for it to become the tail (that's why the reverse ordering) and then modify it. > t=$t:l # Downcase the tail > t=$h:gs/ /_/ And I forgot that braces are needed because of the space: t=${t:gs/ /_/} > mv $f $h$t > > The last five steps could be written as > > mv $f ${${:-$h$t}:l:gs/ /_/} Rather: mv $f $h${t:l:gs/ /_/} which isn't nearly as mysterious. Oh well. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-16 21:44 ` Bart Schaefer @ 2000-06-17 1:17 ` Clint Adams 0 siblings, 0 replies; 8+ messages in thread From: Clint Adams @ 2000-06-17 1:17 UTC (permalink / raw) To: Bart Schaefer; +Cc: zsh-users > Oh, and your solution missed file names that began with a dot, unless you > meant to say that both MARK_DIRS and GLOB_DOTS were needed ... No, I didn't. I hadn't considered dotfiles, actually. > The correct solution is > > for f in **/*(DNOn^M); do > mv -v $i ${${(M)i%/*}:+${i%/*}}${${${(M)i%/*}:-$i}:l:gs/ /_/} > done Of course, you meant to change all the i's to f's or the f to an i. Thanks for the shorter version. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-16 18:53 more fun with parameter expansion Clint Adams 2000-06-16 19:54 ` Clint Adams 2000-06-16 21:00 ` Bart Schaefer @ 2000-06-18 22:02 ` Peter Stephenson 2000-06-19 9:08 ` Peter Stephenson 2 siblings, 1 reply; 8+ messages in thread From: Peter Stephenson @ 2000-06-18 22:02 UTC (permalink / raw) To: zsh-users Clint Adams wrote: > This is for someone who wants to take a directory tree and convert all > the filenames (and directory names) to lowercase, replacing spaces > with underscores. It presumes that you are using GNU mv and have > MARK_DIRS set. I'm sure that someone can make it more efficient. > > for i (*(/N)) {mv -v "$i" "${(L)i:gs/ /_/}"} > for i (*/**/*(/N)) {mv -v "${${(L)i%/*/}:gs/ /_/}/${${${i#*/}%/}##*/}" "${(L) > i:gfor i (**/*(N^/)) {mv -v "${i}" "${(L)i:gs/ /_/}"} See zmv in the Functions/Misc directory of 3.1.9 (this version is needed for it to work). zmv '(**/)(*[ A-Z]*)' '${1}${(L)2/ /_}' works on a simple test case (use the option -n just to test what it would do). Each parenthesis maps to a positional parameter; (**/) is a special case and is the only sort of multi-directory pattern that works. Looks like zmv needs the option to ignore files whose names didn't change (it's a pain having to make the LH pattern so specific). I'd appreciate any feedback about zmv. -- Peter Stephenson <pws@pwstephenson.fsnet.co.uk> Work: pws@CambridgeSiliconRadio.com Web: http://www.pwstephenson.fsnet.co.uk ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-18 22:02 ` Peter Stephenson @ 2000-06-19 9:08 ` Peter Stephenson 2000-06-19 15:21 ` Clint Adams 0 siblings, 1 reply; 8+ messages in thread From: Peter Stephenson @ 2000-06-19 9:08 UTC (permalink / raw) To: Zsh users list I wrote: > Clint Adams wrote: > > This is for someone who wants to take a directory tree and convert all > > the filenames (and directory names) to lowercase, replacing spaces > > with underscores. > > See zmv in the Functions/Misc directory of 3.1.9 (this version is needed > for it to work). > > zmv '(**/)(*[ A-Z]*)' '${1}${(L)2/ /_}' > > works on a simple test case (use the option -n just to test what it would > do). However, it didn't do depth-first matching, so things like `MYDIR/MYFILE' were screwed up because it tried to rename MYDIR to mydir, then MYDIR/MYFILE (which didn't exist) to MYDIR/myfile. Luckily, there are now glob qualifiers to do depth-first ordering: **/*(odon) orders first by depth under a given directory, then by name. > Looks > like zmv needs the option to ignore files whose names didn't change (it's a > pain having to make the LH pattern so specific). I've made this the default. I can't see why you would want the error. Now you should be able to do zmv '(**/)(*)' '${1}${(L)2// /_}' (I should have put the doubled slash in last time). I'm sending this to zsh-users, because you can always copy an installed zmv and patch it yourself. Index: Functions/Misc/zmv =================================================================== RCS file: /cvsroot/zsh/zsh/Functions/Misc/zmv,v retrieving revision 1.2 diff -u -r1.2 zmv --- Functions/Misc/zmv 2000/05/05 14:14:12 1.2 +++ Functions/Misc/zmv 2000/06/19 09:02:41 @@ -61,10 +61,11 @@ # other words, parenthesising of wildcards is independent of any existing # parentheses. # -# Any error --- a substitution resulted in an empty string, a -# substitution did not change the file name, 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. +# 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 @@ -76,7 +77,8 @@ # -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. +# -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> @@ -119,7 +121,7 @@ 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 pat repl errstr fpat +local pat repl errstr fpat hasglobqual opat typeset -A from to integer stat @@ -190,17 +192,29 @@ 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 files=(${~fpat}) -if [[ -o bareglobqual && $pat = (#b)(*)\([^\)\|\~]##\) ]]; then - # strip off qualifiers for use as ordinary pattern - pat=$match[1] -fi +[[ -n $hasglobqual ]] && pat=$opat errs=() @@ -219,7 +233,9 @@ if [[ -z $g ]]; then errs=($errs "$f expanded to empty string") elif [[ $f = $g ]]; then - errs=($errs "$f not altered by substitution") + # don't cause error: more useful just to skip + # errs=($errs "$f not altered by substitution") + continue elif [[ -n $from[$g] && ! -d $g ]]; then errs=($errs "$f and $from[$g] both map to $g") elif [[ -f $g && -z $opt_f ]]; then -- Peter Stephenson <pws@cambridgesiliconradio.com> Cambridge Silicon Radio, Unit 300, Science Park, Milton Road, Cambridge, CB4 0XL, UK Tel: +44 (0)1223 392070 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: more fun with parameter expansion 2000-06-19 9:08 ` Peter Stephenson @ 2000-06-19 15:21 ` Clint Adams 0 siblings, 0 replies; 8+ messages in thread From: Clint Adams @ 2000-06-19 15:21 UTC (permalink / raw) To: Peter Stephenson; +Cc: Zsh users list > zmv '(**/)(*)' '${1}${(L)2// /_}' MARK_DIRS raises its ugly head again. Changing the odon's to odon^M made it work as advertised. ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2000-06-19 15:22 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2000-06-16 18:53 more fun with parameter expansion Clint Adams 2000-06-16 19:54 ` Clint Adams 2000-06-16 21:00 ` Bart Schaefer 2000-06-16 21:44 ` Bart Schaefer 2000-06-17 1:17 ` Clint Adams 2000-06-18 22:02 ` Peter Stephenson 2000-06-19 9:08 ` Peter Stephenson 2000-06-19 15:21 ` Clint Adams
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).