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 thewho
output uses tabs as separators. It may be easier to read too. Thesed
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 usernamemary
matching the usernamemary.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 namet.m
matching the nametim
. The--
prevents a leading hyphen in"$name"
being treated as agrep
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 togrep
wouldn't be useful here because valid names may contain non-word characters (e.g.t.m
).sort -u
takes the output of thefor
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 touniq
, 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.