1

I've got this code which reads an example file of /etc/passwd:

#!/bin/bash

OLDIFS=$IFS
IFS=$'\n'

while read linea resto
do
        echo $linea
        echo $resto
        if [[ $(echo $linea | cut -d: -f6 | egrep -c 'al-03-04') == 1 ]]
        then
                finger $(cut -d: -f1) 2> fich
                if [[ $(egrep -c fich) == 1 ]]
                then
                        echo $(echo $linea | cut -d: -f1). Inactive user
                else
                        echo $(echo $linea | cut -d: -f1). Active user
                fi
        fi
done < <(cat fichpasswd)

IFS=$OLDIFS

and this is the example file of /etc/passwd:

jfer:x:5214:1007:Javier Lopez,,,:/home/al-03-04/jfer:/bin/bash
jperez:x:10912:1009:Juan Perez,,,:/home/al-03-04/jperez:/bin/bash
mfernan:x:10913:1009:Manuel Fernandez,,,:/home/al-02-03/mfernan:/bin/bash

The problem is that the while loop only reads the first line, ignoring the others. The script's output is:

jfer:x:5214:1007:Javier Lopez,,,:/home/al-03-04/jfer:/bin/bash

jfer. Active user
4
  • It seems the problem is the egrep part, namely its -c switch. When I remove it, I'm getting the output for all the lines (just note that $resto is always empty, as read always reads just one line, $IFS is used only to split the line into parts). Commented Jun 16, 2018 at 10:30
  • Btw.: Take a look: shellcheck.net Commented Jun 16, 2018 at 10:43
  • @choroba I don't think that the problem is the egrep part. It seems to be a reasonable choice to skip the lines that doesn't contain al-03-04 exactly one time. I think the problem is mainly the IFS part (there is at least two errors, you could see my answer to get more details). Commented Jun 16, 2018 at 11:16
  • There are multiple process substitutions in your code (e.g. $(cut -d: -f1) where you missed to supply a filename so it will eat up your stdin after read has read the first line. Commented Jun 16, 2018 at 11:42

1 Answer 1

3

You could try something like :

#!/bin/bash

FILE="test.txt"

while IFS=":" read -a data; do
  echo "${data[@]}"
  if [[ $(echo ${data[5]}|egrep -c 'al-03-04') -eq 1 ]]; then
    if [[ $(finger "${data[0]}" 2>&1) =~ "no such user" ]]; then
      echo "${data[0]}. Inactive user"
    else
      echo "${data[0]}. Active user"
    fi
  fi
done < "$FILE"

Here's the output :

ineumann ~ $ cat test.txt 
ineumann:x:5214:1007:Javier Lopez,,,:/home/al-03-04/jfer:/bin/bash
jperez:x:10912:1009:Juan Perez,,,:/home/al-03-04/jperez:/bin/bash
mfernan:x:10913:1009:Manuel Fernandez,,,:/home/al-02-03/mfernan:/bin/bash
ineumann ~ $ ./test.sh 
ineumann x 5214 1007 Javier Lopez,,, /home/al-03-04/jfer /bin/bash
ineumann. Active user
jperez x 10912 1009 Juan Perez,,, /home/al-03-04/jperez /bin/bash
jperez. Inactive user
mfernan x 10913 1009 Manuel Fernandez,,, /home/al-02-03/mfernan /bin/bash

A few comments on your script :

  • No need to use cat to read your file in a loop.
  • finger $(cut -d: -f1) 2> fich : cut need an input. And no need to use a temporary file to catch the output of finger (moreover this is not thread safe).
  • No need to use cut in your script when you choose the right IFS to split a line in multiple parts. In your case, I think the smartest choice would be :.
  • You can change the IFS only inside the loop with the syntax while IFS=':' read; do ...; done. No need to re-assign IFS with OLDIFS.
  • You can also use the while IFS=':' read var1 var2 var3 trash; do ...; done syntax to avoid to use an array with read -a (but I'd prefer to use an array as I wrote in my version of your script).
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.