zsh-users
 help / color / mirror / code / Atom feed
* Is this the Zsh way for doing this?
@ 2004-03-25 22:32 DervishD
  2004-03-28  0:55 ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: DervishD @ 2004-03-25 22:32 UTC (permalink / raw)
  To: Zsh Users

    Hi all :)

    WARNING: this is one of my long messages, lots of text ahead!

    I have a text file with the following format:

Album title: 'Elemental'	[from Loreena McKennitt]
Track  1: 'Blacksmith'
Track  2: 'She Moved Through The Fair'
Track  3: 'Stolen Child'
Track  4: 'The Lark In The Clear Air '
Track  5: 'Carrighfergus'
Track  6: 'Kellswater'
Track  7: 'Banks Of Claudy'
Track  8: 'Come By The Hills'
Track  9: 'Lullaby'
Track 10: 'This song really doesn't exist...'

    (This album is quite good, BTW)

    The song number 10 is just to show that the special case. I want
to take the information from this file and use it to rename a bunch
of audio files whose names are of the form 'audio_XX.cdr', where 'XX'
is a number between 00 and 99. I do it like that (I use 'print'
instead 'mv' for testing, as well as the separator "-->"):

tail +2 .CDinfo | while read song
do
    print audio_${(l.2..0.)${song##Track ##}%%:*}.cdr \
    "-->" \
    ${song/#(#b)Track #([0-9]##):'(*)'/${(l.2..0.)match[1]}.${match[2]}}.cdr
done

    The 'tail +2' is for getting rid of the 'Album title' line. After
that I build the name of the audio file using 'song', deleting all
except the number from each line of the file (althoug this can be
done using brace expansion, or a counter, etc...). The new name is
build taking the line again, deleting the 'Track ' part. We then take
the number, pad it to two digits with 0's and replacing the name of
the song without the quotes. AFAIK, when pattern matching takes place
at the point of the "'(*)'", it is implicitly anchored to the end of
the string and is the longest match, so the replacement will
substitute a string like "'It's a string'o'sample'" for "It's a
string'o'sample", and not by "It's a string'o" or "s a string",
etc... The paddings are needed since the song number can have one or
two digits and I want numeric sort in the directory listing without
using the 'n' globbing flag.

    The result is a series of 'mv' commands like:

    mv audio_07.cdr 07.The name of the freakin' song.cdr

    What I want to know is if this is a correct way or if I'm missing
something that will be do the same in a much more clever way, and why
I cannot use the (#b) flag before the '/' (together with 'song') or
before the '#' (which indicates that 'Track' must match at the
beginning of the string). BTW, is that '#' necessary or not? Do I
need to specify too the end of the string anchor?

    Thanks a lot in advance and sorry for the long message. At least
the Loreena McKennitt CD is quite good O:))

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736
http://www.pleyades.net & http://raul.pleyades.net/


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

* Re: Is this the Zsh way for doing this?
  2004-03-25 22:32 Is this the Zsh way for doing this? DervishD
@ 2004-03-28  0:55 ` Bart Schaefer
  2004-03-28  1:03   ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2004-03-28  0:55 UTC (permalink / raw)
  To: Zsh Users

On Mar 25, 11:35pm, DervishD wrote:
}
} tail +2 .CDinfo | while read song

This is fine, but you might prefer the more obvious:

tail +2 .CDinfo | while read ignored_word track_number track_name
do
    # At this point ignored_word is always "Track" and track_number
    # still has a trailing colon that we need to strip off.  Also
    # track_name contains single quotes, but based on this example:
    #    Track 10: 'This song really doesn't exist...'
    # they aren't balanced single quotes, so we have to strip them.
    # If the zero-padding gets done here too, it's clearer later.
    track_number=${(l.2..0.)${track_number%:}}
    track_name=${${track_name%\'}#\'}

    # At this point you might also want to clean wildcards and slashes
    # out of $track_name, but that's up to you.  Your original doesn't.

    # Now the "mv" command is quite obvious.
    mv audio_${track_number}.cdr "${track_number}.${track_name}.cdr"
done

If you really desperately want to write it all as one command rather
than have the two extra assignments:

    mv  audio_${track_number/

As to your specific pattern-matching questions:

}     ${song/#(#b)Track #([0-9]##):'(*)'/${(l.2..0.)match[1]}.${match[2]}}.cdr
} 
} AFAIK, when pattern matching takes place
} at the point of the "'(*)'", it is implicitly anchored to the end of
} the string and is the longest match

No, it's not implicitly anchored at the end, but it is the longest match,
which (since there is always a single-quote at the end of the string) is
equivalent in this case.

However, you do need to escape the single quotes, and there is a space
after the colon:

	(#b)Track #([0-9]##): \'(*)\'

} [Why can't I] use the (#b) flag before the '/' (together with 'song')
} or before the '#' (which indicates that 'Track' must match at the
} beginning of the string) [...?]

What you've asked is very similar to asking about C,

    Why can't I put the "--" before the "+" or before the "=" in
    the expression "song += --pattern" ?

This is because the / and the # together constitute an operator on the
value of the variable, whereas (#b) is part of the pattern which is an
argument to that operator.

} BTW, is that '#' necessary or not?

It's not necessary as long as none of the names is "The Track 27: song"
or some such.

} Do I need to specify too the end of the string anchor?

No.


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

* Re: Is this the Zsh way for doing this?
  2004-03-28  0:55 ` Bart Schaefer
@ 2004-03-28  1:03   ` Bart Schaefer
  2004-03-28 20:07     ` DervishD
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2004-03-28  1:03 UTC (permalink / raw)
  To: Zsh Users

On Mar 28, 12:55am, Bart Schaefer wrote:
}
} If you really desperately want to write it all as one command rather
} than have the two extra assignments:
} 
}     mv  audio_${track_number/

Oops, that got cut off in mid-thought.  Here's the whole thing:

    mv audio_${(l.2..0.)track_number/#(#b)([0-9]#):/$match[1]}.cdr \
        ${(l.2..0.)match[1]}.${${track_name%\'}#\'}.cdr


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

* Re: Is this the Zsh way for doing this?
  2004-03-28  1:03   ` Bart Schaefer
@ 2004-03-28 20:07     ` DervishD
  2004-03-28 21:00       ` Bart Schaefer
  0 siblings, 1 reply; 6+ messages in thread
From: DervishD @ 2004-03-28 20:07 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

    Hi Bart :)

    Thanks a lot for your answer :)

 * Bart Schaefer <schaefer@brasslantern.com> dixit:
> } tail +2 .CDinfo | while read song
> This is fine, but you might prefer the more obvious:
> tail +2 .CDinfo | while read ignored_word track_number track_name

    I *always* forget that 'read' can be used with more than one
parameter O:) This way, using IFS, it can be used as a simple
tokenizer.

>     # At this point ignored_word is always "Track" and track_number
>     # still has a trailing colon that we need to strip off.  Also
>     # track_name contains single quotes, but based on this example:
>     #    Track 10: 'This song really doesn't exist...'
>     # they aren't balanced single quotes, so we have to strip them.

    Yes, they're always balanced, is the output from cdda2wav.

>     # At this point you might also want to clean wildcards and slashes
>     # out of $track_name, but that's up to you.  Your original doesn't.

    No, it doesn't because I didn't thought of it :( Thanks for
pointing. Could it be solved using the (q) flag or should I use ${//}
and substitute every dangerous character for a safe version?

> If you really desperately want to write it all as one command rather
> than have the two extra assignments:
> 
>     mv audio_${(l.2..0.)track_number/#(#b)([0-9]#):/$match[1]}.cdr \
>         ${(l.2..0.)match[1]}.${${track_name%\'}#\'}.cdr

    Thanks for the recipe :))
 
> As to your specific pattern-matching questions:
> }     ${song/#(#b)Track #([0-9]##):'(*)'/${(l.2..0.)match[1]}.${match[2]}}.cdr
> } AFAIK, when pattern matching takes place
> } at the point of the "'(*)'", it is implicitly anchored to the end of
> } the string and is the longest match
> No, it's not implicitly anchored at the end, but it is the longest match,
> which (since there is always a single-quote at the end of the string) is
> equivalent in this case.

    Nice, then.
 
> However, you do need to escape the single quotes, and there is a space
> after the colon:

    Sorry, they are, but when I copied the command line it got mangled
:(, don't know why (I would swear I copied it from my .history, but
obviously I didn't because it is correctly shown there :?).

> 	(#b)Track #([0-9]##): \'(*)\'
> } [Why can't I] use the (#b) flag before the '/' (together with 'song')
> } or before the '#' (which indicates that 'Track' must match at the
> } beginning of the string) [...?]
> What you've asked is very similar to asking about C,
> 
>     Why can't I put the "--" before the "+" or before the "=" in
>     the expression "song += --pattern" ?
> This is because the / and the # together constitute an operator on the
> value of the variable, whereas (#b) is part of the pattern which is an
> argument to that operator.

    Ok. I don't know why I thought that the globbing flags could be
used at any point in the expression involving patterns, because the
manual clearly states that they 'affect any text to their right up
to the end of the enclosing group or to the end of the pattern'.
Sorry for the noise O:(

> } BTW, is that '#' necessary or not?
> It's not necessary as long as none of the names is "The Track 27: song"
> or some such.

    So it is necessary for me, because I don't know what kind of
names this function may get.

    Again, Bart, thanks a lot for your invaluable help. I can't think
of a way of returning you all you do for people like me :) You're
great, I really mean it.

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736
http://www.pleyades.net & http://raul.pleyades.net/


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

* Re: Is this the Zsh way for doing this?
  2004-03-28 20:07     ` DervishD
@ 2004-03-28 21:00       ` Bart Schaefer
  2004-03-29 14:08         ` DervishD
  0 siblings, 1 reply; 6+ messages in thread
From: Bart Schaefer @ 2004-03-28 21:00 UTC (permalink / raw)
  To: Zsh Users

On Mar 28, 10:07pm, DervishD wrote:
}
}     Thanks a lot for your answer :)

No problem; you're welcome.

} >     # At this point you might also want to clean wildcards and slashes
} >     # out of $track_name, but that's up to you.  Your original doesn't.
} 
}     No, it doesn't because I didn't thought of it :( Thanks for
} pointing. Could it be solved using the (q) flag or should I use ${//}
} and substitute every dangerous character for a safe version?

The substituion is necessary for slashes, because you can't even create a
file with slashes in the name.

The (q) flag is _not_ necessary for other metacharacters when creating
the file (the argument to "mv" is already double-quoted); the problem
would be with manipulating the names later.  So doing either nothing or
the substitution is appropriate in that case.


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

* Re: Is this the Zsh way for doing this?
  2004-03-28 21:00       ` Bart Schaefer
@ 2004-03-29 14:08         ` DervishD
  0 siblings, 0 replies; 6+ messages in thread
From: DervishD @ 2004-03-29 14:08 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh Users

    Hi Bart :)

 * Bart Schaefer <schaefer@brasslantern.com> dixit:
> } >     # At this point you might also want to clean wildcards and slashes
> } >     # out of $track_name, but that's up to you.  Your original doesn't.
> }     No, it doesn't because I didn't thought of it :( Thanks for
> } pointing. Could it be solved using the (q) flag or should I use ${//}
> } and substitute every dangerous character for a safe version?
> The substituion is necessary for slashes, because you can't even create a
> file with slashes in the name.

    Of course, I didn't think of it, but a song name may have any
character :( Well, that's simple using ${/\/|/} on the appropriate
parameter, or something like that.
 
> The (q) flag is _not_ necessary for other metacharacters when creating
> the file (the argument to "mv" is already double-quoted); the problem
> would be with manipulating the names later.  So doing either nothing or
> the substitution is appropriate in that case.

    Manipulating the names later is not a problem, since Zsh behaves
quite well quoting when completing, etc... The only problem could be
names starting with '-', but almost all Linux utilities admit '--' as
end-of-options separator. 

    Again, thanks for your useful advice :)

    Raúl Núñez de Arenas Coronado

-- 
Linux Registered User 88736
http://www.pleyades.net & http://raul.pleyades.net/


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

end of thread, other threads:[~2004-03-29 14:48 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-03-25 22:32 Is this the Zsh way for doing this? DervishD
2004-03-28  0:55 ` Bart Schaefer
2004-03-28  1:03   ` Bart Schaefer
2004-03-28 20:07     ` DervishD
2004-03-28 21:00       ` Bart Schaefer
2004-03-29 14:08         ` DervishD

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