
Wednesday July 14, 2004
ksh scripting #4 : list elements v7 and v8
Alan offered cool advise on ksh scripting #3 with pl.sh using "IFS" and "set --".
... and I dig!
So I adapted pl.sh into a shell function. My initial concerns that IFS is not taken in local context of a function was valid afterall. IFS is global and most certainly not just another variable. It got confusing when echo $IFS doesn't show anything and I thought it's spaces. set | grep IFS shows differently. It got even more mysterious when the function was invoked again but produce different result. Only after a bunch of almighty debug printf (ok I used echo) that it became clear IFS was causing my confusion. Just to make matter more difficult for myself I tried to be fancy and do set -- $@ directly. That certainly doesn't work. The moment IFS is set, substitution for $@ no longer shows the char that's IFS but instead, space is substituted!
Here's pl7() which adapted the set -- trick that works:
#
# pl7 - print list elements delimited by '|'
#
function pl7 {
l=$@
IFS='|'
set -- $l
for e
do
echo $e
done
unset IFS
}
And to add some flexibility, I can cater to user specified delimiters which would have been otherwise messy to do in pl version 1:
#
# pl8 - print list elements, $1 is delimiter
#
function pl8
{
d=$1
shift
l=$@
IFS=$d
set -- $l
for e
do
echo $e
done
unset IFS
}
Give it a go:
$ pl7 "lp|x|71|8|Line Printer Admin|/usr/spool/lp|"
lp
x
71
8
Line Printer Admin
/usr/spool/lp
xxx
$ pl8 ":" lp:x:71:8:Line Printer Admin:/usr/spool/lp:
lp
x
71
8
Line Printer Admin
/usr/spool/lp
xxx
$
I guess my intention was clear, in that I'm trying to let ksh do all the work whenever I can avoid a process invocation. Otherwise, it's really much easier to just awk it.
$ head -1 /etc/passwd | nawk -F':' '{while (++i<=NF) print $i}'
or a bit more readable
$ head -1 /etc/passwd | nawk -F':' '{for (i=1;i<=NF;i++) print $i}'
PS: Okay why version 7 and 8? it took me that no. of iteration to figure out IFS. ;)
ksh scripting flashback:
#1
#2
#3
(2004-07-14 00:00:04.0)
Permalink
|
What about: $ head -1 /etc/passwd | tr ":" "\n" or $ head -1 /etc/passwd | awk 'BEGIN{RS=":"}{print}' interestingly, it seems that /usr/bin/tr is not that slow: $wc -l my.passwd 5000 my.passwd $ time cat my.passwd | tr ":" "\n" > /dev/null real 0m0.02s user 0m0.02s sys 0m0.01s $ time awk 'BEGIN { RS = ":"}{print}' my.passwd > /dev/null real 0m0.16s user 0m0.16s sys 0m0.00s $ time nawk -F':' '{for (i=1;i<=NF;i++) print $i}' my.passwd > /dev/null real 0m0.07s user 0m0.06s sys 0m0.00sPosted by antoon on July 22, 2004 at 06:11 AM PDT #
Posted by tom on August 27, 2004 at 05:04 PM PDT #
I never like messing with IFS so this one will do it:
function pl_cjg { typeset line=$2 while [[ ${line%%${1:-:}*} != ${line} ]] do echo ${line%%${1:-:}*} line=${line#*${1:-:}} done echo ${line} }Though for parsing whole file this is better
function pl_file { typeset line while read line do while [[ ${line%%${1:-:}*} != ${line} ]] do echo ${line%%${1:-:}*} line=${line#*${1:-:}} done echo ${line} donePosted by Chris Gerhard on October 21, 2004 at 07:33 AM PDT #