Home > Blockchain >  Users who are logged on, in alphabetical order, printed on one line
Users who are logged on, in alphabetical order, printed on one line

Time:03-06

Users who are logged on, in alphabetical order, printed on one line.

What are the minimum amount of changes to get this to work because in a bash script?

this is the given script:

for name in $@
do
    who | grep -w "^name" | sed 's/ .*//' | uniq
done | sort | tr '\n' ' '
echo

CodePudding user response:

Single line commands:

who | awk '{print $1}' | sort | uniq | tr '\n' ' '
  • who: list of logged in users.
  • awk '{print $1}': keep only the first word or each line, which is the usernames.
  • sort: put the usernames in alphabetical order.
  • uniq: remove duplicates.
  • tr '\n' ' ': remove carriage returns, and replace them with spaces.

Ex

$ who
steve    tty7         Mar  5 16:25 (:0)
bernard  tty7         Mar  5 16:25 (:0)
sarah    tty7         Mar  5 16:25 (:0)

$ who | awk '{print $1}' | sort | uniq | tr '\n' ' '
bernard sara steve

Your code did grep -w "^name", which tells grep to output the lines that start with "name". Not the lines that begin with the value of variable "name". For that you would need to do grep -w "^$name".

CodePudding user response:

Try this Shellcheck-clean code:

for name in "$@"
do
    who | sed 's/[[:space:]].*//' | grep -xF -- "$name"
done | sort -u | paste -sd ' '
  • $@ should always have double quotes on it ("$@"). See Accessing bash command line args $@ vs $*. Shellcheck correctly complains if double quotes are not used.
  • sed 's/[[:space:]].*//' removes the first whitespace character, and everything after it, on every input line. Using [[:space:]] instead of a literal space character means that the code will still work if the who output uses tabs as separators. It may be easier to read too. The sed command is run first to ensure that usernames occupy whole lines so it's easier to avoid spurious matches at the next pipeline stage.
  • grep -xF -- "$name" searches for whole lines in the input that are the "$name" string. The -x option forces matching of whole lines. That prevents, for instance, the username mary matching the username mary.jane (a valid username on at least some Linux systems). The -F option means that regular expression patterns in "$name" are treated as literal strings. That prevents, for instance, the name t.m matching the name tim. The -- prevents a leading hyphen in "$name" being treated as a grep option. No system that I know of allows usernames to have leading hyphens, but there's nothing to stop such an invalid name being provided as a command line argument to the code. The -w option to grep wouldn't be useful here because valid names may contain non-word characters (e.g. t.m).
  • sort -u takes the output of the for loop (an unsorted list of usernames, one per line, possibly with repetitions) and sorts it. The -u option causes it to remove duplicates (like piping to uniq, but saves a process creation).
  • paste -sd ' ' puts all the lines in to input on a single line, separated by spaces (specified by the -d option and ' ' (space) option argument), and terminated with a newline character. tr '\n' ' ' would have a similar effect but it produces an unterminated line with a trailing space character.
  •  Tags:  
  • bash
  • Related