Don't do while read | cut
. Use IFS as:
#!/bin/sh
while IFS=: read name passwd uid gid gecos home shell; do
if test "$shell" = /bin/bash; then
echo "$name"
fi
done < /etc/passwd
But for this particular use case, it's probably better to do:
awk '$7 == "/bin/bash"{print $1}' FS=: /etc/passwd
The issue your code has is a common error. Consider the line:
if [ $("$line" | cut -d : -f 7)=="/bin/bash" ]
Assume you have a value in $line
in which the final field is /bin/dash
. The process substitution will insert the string /bin/dash
, and bash will attempt to execute:
if [ /bin/dash==/bin/bash ]
since /bin/bash==/bin/bash
is a non-empty string, the command [ /bin/bash==/bin/bash ]
returns succesfully. It does not perform any sort of string comparison. In order for [
to do a string comparison, you need to pass it 4 arguments. For example, [ /bin/dash = /bin/bash ]
would fail. Note the 4 arguments to that call are /bin/dash
, =
, /bin/bash
, and ]
. [
is an incredibly bizarre command that requires its final argument to be ]
. I strongly recommend never using it, and replacing it instead with its cousin test
(very closely related, indeed both test
and [
used to be linked to the same executable) which behaves exactly the same but does not require its final argument to be ]
.