[clug] Bash questions...
Kevin Pulo
kev at pulo.com.au
Tue May 3 02:48:04 MDT 2011
On Mon, May 02, 2011 at 04:10:26PM +1000, David Deaves wrote:
> There are some very cool things you can do with strings in modern bash, you
> almost never need to fork to some other more capable program (sed, expr, awk ...)
This is true, and usually great fun, too.
> of interest the old standards basename and dirname are easily re-implemented
> with the "${path##*/}" (the single arg usage) and "${path%/*}".
And with shopt -s extglob, you can do all sorts of stuff with these
operators.
> To do the more complete 2 arg basename you would need:
>
> bname()
> {
> file="${1##*/}"
> echo "${file%$2}"
> }
>
> all fork free.
Unfortunately, that will generally cost you 1 fork, because to use it
you typically need to do something like:
foo="$(bname "$full" "$ext")"
And the shell needs to fork to capture the stdout from bname (since
you're using echo to return the result).
You can see this by checking the final column of /proc/loadavg, which
is the most recent pid handed out by the kernel. But you need to be
careful that you don't spawn any processes in you attempt to read it.
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.01 0.05 0.05 1/463 6246
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.01 0.05 0.05 1/463 6246
$ bname() { file="${1##*/}" ; echo "${file%$2}" ; }
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY ; bname ; exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.01 0.05 0.05 1/463 6284
0.01 0.05 0.05 2/463 6284
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY ; foo=$(bname) ; exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.01 0.04 0.05 1/463 6373
0.01 0.04 0.05 2/463 6374
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY ; foo=$(bname) ; exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.01 0.04 0.05 1/463 6385
0.01 0.04 0.05 2/463 6386
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY ; foo=$(bname) ; exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.01 0.04 0.05 1/463 6386
0.01 0.04 0.05 2/463 6387
$
Thankfully 1 fork() isn't a very big deal these days. But this can be
very annoying when the function in question has side-effects, eg. it
sets the value of some other (global) variable, because it'll happen
in the sub-process, and you'll never see it in the "main" program.
To get around this (when it does matter), I tend to do things in a
tcl-ish kind of way, passing in the name of the variable to put the
result into, eg:
$ function bname { local file="${2##*/}" ; eval "$1="'${file%$3}' ; }
$ exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY ; bname result /foo/bar/baz.txt .txt ; echo $result ; exec 3< /proc/loadavg ; read -u 3 ; echo $REPLY
0.00 0.04 0.05 1/462 11553
baz
0.00 0.04 0.05 1/462 11553
$
Which is more annoying to code, and less readable.
And, a point of nitpicking, $file should be declared local. :)
Kev
--
Kevin Pulo
kev at pulo.com.au
http://www.kev.pulo.com.au/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
URL: <http://lists.samba.org/pipermail/linux/attachments/20110503/782ad391/attachment.pgp>
More information about the linux
mailing list