15

I wonder why this script continues to run even with an explicit exit command.

I have two files:

file1.txt with the following content:

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
ffffff
gggggg

file2.txt with the following content:

111111
aaaaaa
222222
333333
ffffff
444444

The script (test.sh) is this, two nested loops checking if any line of the first file contains any line of the second file. If it finds a match, it aborts.

#!/bin/bash
path=`dirname $0`

cat $path/file1.txt | while read line
do  
    echo $line
    cat $RUTA/file2.txt | while read another
    do
        if [ ! -z "`echo $line | grep -i $another`" ]; then
            echo "!!!!!!!!!!"
            exit 0
        fi              
    done
done 

I get the following output even when it should exit after printing the first !!!!!!!!!!:

aaaaaa
!!!!!!!!!!
bbbbbb
cccccc
dddddd
eeeeee
ffffff
!!!!!!!!!!
gggggg

Isn't exit supposed to end the execution of the script altogether?

YowE3K
  • 23,852
  • 7
  • 26
  • 40
Tulains Córdova
  • 2,559
  • 2
  • 20
  • 33
  • 1
    The only reason I can think of is due to the pipe into `while`. The pipe will kick off another subprocess (shell) for the `while`, so the `exit` within the `while` exits that shell and your back to your original. – lurker Aug 21 '13 at 14:27

2 Answers2

19

The reason is that the pipes create sub processes. Use input redirection instead and it should work

#!/bin/bash

while read -r line
do
    echo "$line"
     while read -r another
    do
        if  grep -i "$another" <<< "$line" ;then
            echo "!!!!!!!!!!"
            exit 0
        fi
    done < file2.txt
done < file1.txt

In the general case, where the input comes from another program and not from a file, you can use process substitution

while read -r line
do
    echo "$line"
     while read -r another
    do
        if  grep -i "$another" <<< "$line" ;then
            echo "!!!!!!!!!!"
            exit 0
        fi
    done < <(command2)
done < <(command1)
user000001
  • 32,226
  • 12
  • 81
  • 108
  • 1
    Thanks... What if instead of files I need to compare the output of too commands ? How could I use input redirection with that ? I tried <<< command but it didn't work... I happened to use the file1 file2 example in order to simplify the question, but I'm really comparing the output of two commands. – Tulains Córdova Aug 21 '13 at 14:46
  • Then you should use [process substitution](http://tldp.org/LDP/abs/html/process-sub.html). For example: `while read -r line; do #commands; done < <(othercommand)` – user000001 Aug 21 '13 at 14:48
  • You blew me away! Bash is so idiomatic. – Tulains Córdova Aug 21 '13 at 14:52
  • 2
    Helped me so much! Had a cat file | to a while loop and it just did not want to exit the script. It would exit the loop only. Switched to input redirect and the exit worked. Thanks! – Nick Constantine Dec 05 '17 at 21:35
6

The while loops are running in their respective shells. Exiting one shell does not exit the containing ones. $? could be your friend here:

            ...
            echo "!!!!!!!!!!"
            exit 1
        fi
    done
    [ $? == 1 ] && exit 0;
done
svante
  • 1,375
  • 8
  • 9