newbie question on Tcl with awk 
Author Message
 newbie question on Tcl with awk

Hello,

I'm only 3 days into learning Tcl and Tk and I've been converting old
Unix admin scripts into Tcl.  One of the scripts uses awk to gain a list
of user names on the system.  The Unix command line looks like this:

who | awk '{ print $1 }' - || sort | uniq

Now, when I attempt to do the same thing in Tcl (wish8.0 actually), the
code looks like this:

set get_users {who | awk '{ print $1 }' - | sort | uniq }
set usernames [ eval exec $get_users ]

This results in an error of:
       can't read "1": no such variable while executing
           "exec who | awk '{print $1}' - sort | uniq"

Anyway, I understand that the $1 is interpreted as a Tcl variable name.
Unfortunately, I neeed the $1 for the awk so that only the user name
from the "who" is output into the list.  Now, maybe I don't need awk at
all and I can just do the whole thing with Tcl.   Any ideas?  I tried
the \$ (to get it to interpret it as literal $, but that failed.  Also
tried the quotes around the "who" command, but then it doesn't
understand the command.

Help!

from the Newbie



Sat, 25 Nov 2000 03:00:00 GMT  
 newbie question on Tcl with awk

A Tcl solution, without awk:

set userinfo [exec who]
set userinfo [split $userinfo "\n"]
foreach line $userinfo {
        set user [lindex $line 0]
        set uniq($user) 1

Quote:
}

puts [lsort [array names uniq]]

This splits the output of who into a list of lines, extracts the
usernames from the line, and stores them in an associative array.  You
then sort the keys in the associative array.  This gives you a list of
sorted, unique users on your machine.

You were right--your code is breaking because Tcl tries to do variable
substitution on $1.  You need to protect the dollar sign from the Tcl
interpreter.  Instead of using a single quote, use curly braces:

exec who | awk {{print $1}} | sort | uniq

The braces signal Tcl to leave the dollar sign alone.  The two sets of
braces are necessary because the first set get stripped off by Tcl, and
the second set are needed by awk to gather the script together as a
single word.

I hope this helps!
Lee

____________________________________________________________

Scriptics Corporation                           <http://www.scriptics.com>

"dedicated to Tcl tools, training, and consulting"



Sat, 25 Nov 2000 03:00:00 GMT  
 newbie question on Tcl with awk



                        .
                        .
                        .

Quote:
>set get_users {who | awk '{ print $1 }' - | sort | uniq }
>set usernames [ eval exec $get_users ]

<URL:http://starbase.neosoft.com/~claird/comp.lang.tcl/fmm.html#awk>
advises you to use
  set get_users {who | awk {{ print $1 }} - | sort | uniq }
instead.
                        .
                        .
                        .
Quote:
>from the "who" is output into the list.  Now, maybe I don't need awk at
>all and I can just do the whole thing with Tcl.   Any ideas?  I tried

                        .
                        .
                        .
  foreach line [split [exec who] \n] {
        lappend list_of_names [lindex $line 0]
  }

comes close.  There's a nearby thread that'll
give you ideas on uniq-ifying $list_of_names.
--

Cameron Laird           http://starbase.neosoft.com/~claird/home.html



Sun, 26 Nov 2000 03:00:00 GMT  
 newbie question on Tcl with awk


Quote:



>                    .
>                    .
>                    .
>  foreach line [split [exec who] \n] {
>        lappend list_of_names [lindex $line 0]
>  }

>comes close.  There's a nearby thread that'll
>give you ideas on uniq-ifying $list_of_names.

                        .
                        .
                        .
Lee F Bernhard posted almost identical content essentially
simultaneously.  Juergen Schoenwaelder followed up with a
scolding that lindex is hazardous in this context.  Juergen's
right, of course, and yet many of us persist in using list-
oriented l* commands to cut up strings.

I'll put something on this in fmm.html in the next week or
so.

Juergen didn't offer positive remedy, so I'll make a few
explicit remarks.  While [split ...] certainly is possible,
what I think most of us do when we *really* want our scripts
to work is something like

         regexp {([^     ]*).*} $line a who_part
         lappend list_of_names $who_part

The regexp admits simplification with the NRE package.  Are
there superior ways to code this same idea?

For newcomers to this topic, I provide an example of what can
happen if a special character appears in an unexpected context:

        % set line "user various stuff { other stuff"
        user various stuff { other stuff
        % lindex $line 0
        user
        % lindex $line 3
        unmatched open brace in list  
--

Cameron Laird           http://starbase.neosoft.com/~claird/home.html



Sun, 26 Nov 2000 03:00:00 GMT  
 newbie question on Tcl with awk


Quote:
>I'm only 3 days into learning Tcl and Tk and I've been converting old
>Unix admin scripts into Tcl.  One of the scripts uses awk to gain a list
>of user names on the system.  The Unix command line looks like this:
>who | awk '{ print $1 }' - || sort | uniq
>Now, when I attempt to do the same thing in Tcl (wish8.0 actually), the
>code looks like this:
>set get_users {who | awk '{ print $1 }' - | sort | uniq }
>set usernames [ eval exec $get_users ]
>This results in an error of:
>       can't read "1": no such variable while executing
>           "exec who | awk '{print $1}' - sort | uniq"

<snipped for brevity>

Quote:
>Now, maybe I don't need awk at all and I can just
>do the whole thing with Tcl.   Any ideas?

This sort of thing is covered in the FAQ, but read on.
The code fragment shown below may give you a few clues
about one way you could access the output of a "who"
command from inside Tcl/Tk, and I have used an associative
array to take the place of the "uniq" part of your command:

# ----- >8 ----- Cut Here ----- 8< -----
set f [open |who r]

if {[catch {pid $f}] == 0} {
    while {! [eof $f]} {
        set len [gets $f line]
        if {$len < 0} {
            break
        }
        # Use a regular expression to match the user names,
        # that is: 1. at the beginning of each line ("^"),
        #          2. a non-space character ("[^ ]"), followed by
        #          3. zero or more non-space characters ("[^ ]*")
        #
        set sts [regexp {^[^ ][^ ]*} $line match]
        if {$sts > 0} {
            set user [string trim $match]

            # Use an associative array to provide a unique list of users
            #
            if {[info exists whosin($user)]} {
                incr whosin($user)
            } else {
                set whosin($user) 1
            }
        }
    }
    close $f

Quote:
}

foreach user [lsort -increasing [array names whosin]] {
    puts $user
Quote:
}

# ----- >8 ----- Cut Here ----- 8< -----

I hope that may help.

Best regards,

Lawson Hanson



Mon, 27 Nov 2000 03:00:00 GMT  
 
 [ 7 post ] 

 Relevant Pages 

1. AWK newbie is looking for a AWK help with his 1st program

2. Newbie awk (sed??) question, regular expressions

3. A Newbie AWK question

4. Newbie question -- to make an awk program act on a collection of files

5. AWK for DOS - NewBie Question

6. newbie awk question

7. awk Newbie question

8. Newbie question: how to learn (N)AWK

9. Newbie question on using System() and Awk

10. Newbie AWK Question

11. AWK Newbie Question

12. Newbie question on Tcl, Oratcl and cgi.tcl

 

 
Powered by phpBB® Forum Software