Home > database >  Basic Linux Bash Scripting while / for
Basic Linux Bash Scripting while / for

Time:10-14

Doing my first steps in bash scripting. Managed to do 5/7 exercices so far, stuck in the last two and I cant find a way to solve it.

Here’s a better translation of the requested exercice, the same should be solved using simple commands like sed, echo, cat, uniq, tr, grep, wc, etc:

Write the command line which displays the number of users whose default shell is one of the shells available on your machine. When the command is executed, for each of the shells we would have a result of the same form as the following:

  • 0 users have for shell / bin / sh
  • 11 users have for shell / bin / bash
  • 0 users have for shell / usr / bin / sh
  • 0 users have for shell / usr / bin / bash

CodePudding user response:

This how I understood your question, One approach using arrays, Associative array included.

#!/usr/bin/env bash

declare -A Shell_and_Users

while IFS=: read -ra lines; do
  login_shell="${lines[-1]}"
  ((Shell_and_Users["$login_shell"]  ))
done < /etc/passwd

To check the value of the associative array Shell_and_Users run:

declare -p Shell_and_Users

Now loop through the associative array to print the desired output.

for i in "${!Shell_and_Users[@]}"; do
  printf -- '- %d users have shell %s\n' "${Shell_and_Users[$i]}" "$i"
done

If that is not the case then edit the question and add more details if the file /etc/shells should be parse/involve, since the solution above will never print 0 users.

CodePudding user response:

You are on the right track. You could use the following script :

#!/bin/bash

# usual syntax to read a file line by line
# https://linuxhint.com/while_read_line_bash/
while IFS= read -r shell
do
   # if our file contains commented lines, we ignore them
   [[ "$shell" =~ ^[[:space:]]*# ]] && continue

   count=$(grep -c ".*:$shell" /etc/passwd)
   echo "- $count users have shell $shell"
done < /etc/shells

Here, /etc/shells is a file containing all available login shell on your system. /etc/passwd is another system file, containing the list of every user on your system, as well as the shell associated with it (format : <username>:XXX:XXX:XXX:XXX:XXX:<shell>)

We use grep -c ".*:$shell" /etc/passwd to find the number of lines in /etc/passwd that end by :<the current shell>

EDIT: if the professor provides you with a list of shell, you can paste them all in a file (i.e., input.txt) and replace done < /etc/shells by done < ./input.txt

CodePudding user response:

Assuming awk can be used, you can try this

$ cat awk.script
#!/usr/bin/env awk -f

BEGIN {
    FS=":"
} $NF=="/bin/bash" {
    count_bash  
    bash=$NF
} $NF=="/usr/bin/bash" {
    count_bash2  
    bash2=$NF
} $NF=="/bin/sh" {
    count_sh  
    sh=$NF
} $NF=="/usr/bin/sh" {
    count_sh2  
    sh2=$NF
} END {
    print count_bash " users have a shell for "bash "\n" \
          count_bash2" users have a shell for "bash2 "\n" \
          count_sh " users have a shell for "sh "\n" \
          count_sh2" users have a shell for "sh2 "\n" \
}

This will give output similar to your expected output, however, if the shell is not in use, you will get an empty output with no value or path which may not be ideal.

Output

$ awk -f awk.script /etc/passwd
24 users have a shell for /bin/bash
 users have a shell for
2 users have a shell for /bin/sh
 users have a shell for
  • Related