-2

I want to check which lines of the file /etc/passwd end with the "/bin/bash" string (field number 7, ":" as delimiter). So far, I've written the following code:

while read line
do
    if [ $("$line" | cut -d : -f 7)=="/bin/bash" ]
    then
        echo $line | cut -d : -f 1
        echo "\n"
    fi
done < /etc/passwd

Currently, executing the script throws errors that show a bad interpretation (most likely due to the syntax). I'd appreciate if you could help me.

jajajaj
  • 7
  • 1
  • I can't understand why so many people pounce on the umpteenth repeat of a problem with an answer rather than looking for a dupe or at least requesting that the error message be provided verbatim (which would make finding an actual dupe [or a solution, as it were]) much easier ... – tink Feb 26 '21 at 17:08

4 Answers4

1

You MUST surround the == operator with spaces. [ and [[ do different things based on how many arguments are given:

if [ "$( echo "$line" | cut -d: -f7 )" == "/bin/bash" ]; ...

I would actually do this: parse the line into fields while you're reading it.

while IFS=: read -ra fields; do
    [[ ${fields[-1]} == "/bin/bash" ]] && printf "%s\n\n" "${fields[0]}"
done < /etc/passwd
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
0

Instead of looping through the rows, and then checking for the /bin/bash part, why not use something like to get all the desired rows, like so:

grep ':/bin/bash$' /etc/passwd

Optionality, you can loop over the rows by using a simple while;

grep ':/bin/bash$' /etc/passwd | while read -r line ; do
    echo "Processing $line"
done
0stone0
  • 34,288
  • 4
  • 39
  • 64
0

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 ].

William Pursell
  • 204,365
  • 48
  • 270
  • 300
0

This line is wrong:

if [ $("$line" | cut -d : -f 7)=="/bin/bash" ]

Also, this is not going to do what you want:

 echo "\n"

Bash echo doesn't understand backslash-escaped characters without -e. If you want to print a new line use just echo but notice that the previous echo:

echo $line | cut -d : -f 1

will add a newline already.

You should always check your scripts with shellcheck. The correct script would be:

#!/usr/bin/env bash

while read -r line
do
    if [ "$(echo "$line" | cut -d : -f 7)" == "/bin/bash" ]
    then
        echo "$line" | cut -d : -f 1
    fi
done < /etc/passwd

But notice that you don't really need a loop which is very slow and could use the following awk one-liner:

awk -v FS=: '$7 == "/bin/bash" {print $1}' /etc/passwd
Arkadiusz Drabczyk
  • 11,227
  • 2
  • 25
  • 38
  • When trying your response, the first operator of the line line if [ "$(echo "$line" | cut -d : -f 7)" == "/bin/bash" ] is unexpected, as the terminal says. I'm kind of newbie to this, could you help me out? – jajajaj Feb 26 '21 at 17:40
  • Just copy my script exactly as it is and run it. – Arkadiusz Drabczyk Feb 26 '21 at 17:45
  • Thank you very much for your answer, I figured out that the mistake was writing == instead of = – jajajaj Feb 26 '21 at 17:49
  • If you like this answer please mark it as solved to let other users know your problem is solved. Also see [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – Arkadiusz Drabczyk Feb 26 '21 at 17:51