views:

180

answers:

7

I'm working with bash and I'm trying to do something like this:

A=1
while [ $A=1 ]; do
    read line
    echo $line | grep test >/dev/null   
    A=$?
    echo $A
done 

This script never ends even when the grep finishes successfully and A is set to 0. What am I missing here? Below is a sample of the output.

$ ./test.sh

asdf

1

test

0

hm...

1
+4  A: 

I find Bash's syntax pretty awful - have you tried something like:

while [ $A -eq 1 ] ... ?

It may be trying to re-assign 1 to $A or something strange like that.

Andy Shellam
or at least put whitespaces between operands and `=` operator.
mouviciel
The = sign is still a comparison in this instance... but it's a string comparison. The whitespace is the crucial aspect
Dancrumb
@Dancrumb good to know guys (not that I do much bash programming!) thanks, Andy.
Andy Shellam
+4  A: 

Try:

while [ $A -eq 1 ]; do
codaddict
The spacing is critical - as written in question with no spaces, the test operator is checking whether '0=1' is an empty string, and it is not so the test passes and the loop continues.
Jonathan Leffler
A: 

Have you not tried this

while [ $A == "1" ]
   ....
done

Edit: Whoops since Dan mentioned my error I graciously admit my mistake and have edited this accordingly - Thanks Dan for the heads up...

while [ $A -eq 1 ]
   ....
done

Sorry! :( Hope this helps, Best regards, Tom.

tommieb75
That's the string comparison operator, not the integer comparison operator
Dancrumb
@Dancrumb: the OP is reading a character input from the bash script...not really an integer....unless you care to explain? Thanks for your input! :)
tommieb75
@tommieb75, sure. The script is putting the return code from a call to grep in $A, so the value is definitely numeric... either a zero or a 1
Dancrumb
@Dancrumb: OMG! never saw that... yeah the $? is the error-level code...whoops my bad....meh! Thanks Dan.... :) Sorry!
tommieb75
+7  A: 

You need to use the correct comparison operator. Bash has different operators for integer and string comparison.

In addition, you need the correct spacing in the comparison expression.

You need

while [ $A -eq 1 ]; do

See here for more

Dancrumb
+1  A: 

you can do this instead. No need to call external grep.

while true; do
    read line
    case "$line" in
      *test* ) break;;
    esac
done 
echo $line
ghostdog74
Interesting. What does the single parenthesis do? And why two semicolons?
Shawn J. Goff
that's part of the case/esac construct. See http://tldp.org/LDP/abs/html/testbranch.html
ghostdog74
A: 

All of your answers are in the Advanced Bash-Scripting guide. It is awesome.

rox0r
+1  A: 

So far all answers (except for ghostdog74's) have focused on the integer/string and spacing problem. While this is correct, I believe the code should be completely re-factored.

Let's say the idea is to process lines until one line matches a regex ('test' in this case). Using grep:

while read line; do      
  grep -q test <<< "$line" && break
  # do something with $line
done

or using double brackets:

while read line; do      
  [[ "$line" =~ test ]] && break
  # do something with $line
done

http://tldp.org/LDP/abs/html/x16608.html http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS

tokland