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
cildoz
  • 436
  • 3
  • 14
  • 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). – choroba Jun 16 '18 at 10:30
  • Btw.: Take a look: http://www.shellcheck.net/ – Cyrus Jun 16 '18 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). – Idriss Neumann Jun 16 '18 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. – Jürgen Hötzel Jun 16 '18 at 11:42

1 Answers1

2

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).
Idriss Neumann
  • 3,760
  • 2
  • 23
  • 32