[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