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