read, echo, printf

Assignment 9

  1. Write a script called read1 that will ask the user to enter a username, then display information about that user. Display the username, UID, and home directory. Hint: /etc/passwd contains the username (field 1), UID (field 3), home directory (field 6).

    Solution:

    # list user info
    
    echo -n "Enter a username: "
    read user junk
    uid=$(grep $user /etc/passwd | cut -d: -f3)
    home=$(grep $user /etc/passwd | cut -d: -f6)
    echo "$user $uid $home"
    
  2. Write a script called read2 that will display information about each user on the system. Display one line per user containing: the username, UID, and home directory.

    Solution:
    This could be done with a one liner, like this:

    cat /etc/passwd | cut -d: -f1,3,6
    

    But in preperation for number 3 it would be better to do it like this:

    # list user info
    
    while read line
    do
        user=$(echo $line | cut -d: -f1)
        uid=$(echo $line | cut -d: -f3)
        home=$(echo $line | cut -d: -f6)
        echo -e "$user\t$uid\t$home"
    done < /etc/passwd
    

    Note that stdin is redirected from /etc/passwd on the done line. This can also be done by piping:

    cat /etc/passwd | 
    while read line
    do
    ...
    done
    
  3. Write a script called read3 the same as above but will add the name of each of the users groups. Hint 1: /etc/group file contains group name (field 1) and names of users that belong to that group (field 4). A user can belong to more than one group. Hint 2: Loop on the lines of /etc/passwd and inside the loop look for groups for each user.

    Solution:

    # list user info
    
    while read line
    do
        #echo $line
        user=$(echo $line | cut -d: -f1)
        uid=$(echo $line | cut -d: -f3)
        home=$(echo $line | cut -d: -f6)
        echo -ne "$user\t$uid\t$home\t"
        echo $(grep $user /etc/group | cut -d: -f1)
    done < /etc/passwd
    
  4. Change the last script (call it read4) to format the output so that each column has enough width, the UID is right justified, and the other fields are left justified.

    Solution:
    Here we do it the hard way. A for loop goes through the groups and concatinates them to the variable groups

    # list user info
                                                                                    
    while read line
    do
        #echo $line
        user=$(echo $line | cut -d: -f1)
        uid=$(echo $line | cut -d: -f3)
        home=$(echo $line | cut -d: -f6)
        groups=
        for group in $(grep $user /etc/group | cut -d: -f1)
        do
            groups="$groups $group"
        done
        printf "%-10s%6d %-20s%s\n" "$user" "$uid" "$home" "$groups"
    done < /etc/passwd
    

    OR tr will get rid of those linefeeds and replace them with spaces:

    # list user info
    
    while read line
    do
        #echo $line
        user=$(echo $line | cut -d: -f1)
        uid=$(echo $line | cut -d: -f3)
        home=$(echo $line | cut -d: -f6)
        groups=$(grep $user /etc/group | cut -d: -f1 | tr '\12' ' ' )
        printf "%-10s%6d %-20s%s\n" "$user" "$uid" "$home" "$groups"
    done < /etc/passwd
    

    OR echo will take a list of arguments and output them with a single space between each. This is also a nice exaple of nested command substitutions.

    # list user info
    
    while read line
    do
        #echo $line
        user=$(echo $line | cut -d: -f1)
        uid=$(echo $line | cut -d: -f3)
        home=$(echo $line | cut -d: -f6)
        groups=$(echo $(grep $user /etc/group | cut -d: -f1) )
        printf "%-10s%6d %-20s%s\n" "$user" "$uid" "$home" "$groups"
    done < /etc/passwd
    

    OR why not just use echo to output the groups? It worked in question 3 and nobody said we have to use printf.

    # list user info
    
    while read line
    do
        #echo $line
        user=$(echo $line | cut -d: -f1)
        uid=$(echo $line | cut -d: -f3)
        home=$(echo $line | cut -d: -f6)
        printf "%-10s%6d %-20s" "$user" "$uid" "$home"
        echo $(grep $user /etc/group | cut -d: -f1)
    done < /etc/passwd