[Novalug] Fill in the blanks?
Jon LaBadie
novalugml@jgcomp.com
Sat Mar 17 22:33:38 EDT 2012
On Sat, Mar 17, 2012 at 07:29:56AM -0400, Michael Henry wrote:
> On 03/16/2012 05:18 PM, James Ewing Cottrell 3rd wrote:
>
> > Quick tutorial on Parameter Selection: consider that # means left and %
> > means right (mnemonic: relative to the $ sign).
>
> Excellent memory device. I wish I'd heard that long ago :-)
For those unclear as to "relative to the $ sign", Jim is refering
to their sequence in the ASCII table.
>
> > [...] so if file is
> > /a/b/c, the ${file#/*} gives /b/c and ${file##/*} gives /c and
> > ${file##*/} gives c.
>
> The first two examples need a slight correction, in case someone
> is puzzling over how the matching works. Here are the three
> examples as generated by Bash:
>
> $ file=/a/b/c
> $ echo "file='${file#/*}'"
> file='a/b/c'
> $ echo "file='${file##/*}'"
> file=''
> $ echo "file='${file##*/}'"
> file='c'
>
> When matched from the left, the pattern '/*' matches a single
> slash and zero or more arbitrary characters. In non-greedy
> mode, zero extra characters are matched, so the pattern matches
> only the leading slash, so the output is 'a/b/c'. In greedy
> mode, this matches the slash and everything that follows, so the
> output is the empty string.
>
I like to think (reword) non-greedy and greedy as shortest match
and longest match. In a shortest match from the left situation
(eg. ${var#/*}) a trailing * is worthless, i.e. /* is the same as /
as the shortest thing that matches * is nothing.
The reverse is true for matches from the right, eg ${var%*/},
a leading, rather than trailing, * is worthless.
Keep in mind that these stripping matches are "anchored" to the
beginning of the string with ${var#...} and to the end of the
string with ${var%...}. Another variable expansion can be used
to deal with substitutions, ${var/old/new} and ${var//old/new}.
$ poem='twinkle tinkle little star'
$ echo ${poem/ti/twi}
twinkle twinkle little star
the above makes only one substitution, use "//" for multiples.
$ poem='tinkle tinkle little star'
$ echo ${poem/ti/twi}
twinkle tinkle little star
$ echo ${poem//ti/twi}
twinkle twinkle little star
> > I would also urge you not to quote arguments unless needed. Quoting
> > rules are simple and worth learning. Echo echoes spaces between
> > arguments, so "echo basename: ${fn%.*}" is fine. Yours gets two spaces.
>
> On the other hand, you have to be careful if you want accurate
> answers for all cases. For example, if a file has multiple
> spaces in a row, the quotes are required:
>
> $ fn='/path/to/multiple spaces.zip'
> $ echo "${fn%.*}"
> /path/to/multiple spaces
> $ echo ${fn%.*}
> /path/to/multiple spaces
>
You are mixing effects of echo and command line processing with variable
expansion. For example, after doing NewFN=$fn, NewFN would have the
same multiple spaces as fn. So you could safely strip the filename
expansion with fn=${fn%.*} without quoting.
jl
--
Jon H. LaBadie jon@jgcomp.com
11226 South Shore Rd. (703) 787-0688 (H)
Reston, VA 20190 (609) 477-8330 (C)
More information about the Novalug
mailing list