Paul Lynch
Paul Lynch

Reputation: 1337

bash while loop with command as part of the expression?

I am trying to read part of a file and stop and a particular line, using bash. I am not very familiar with bash, but I've been reading the manual and various references, and I don't understand why something like the following does not work (but instead produces a syntax error):

while { read -u 4 line } && (test "$line" != "$header_line")
do
  echo in loop, line=$line
done

I think I could write a loop that tests a "done" variable, and then do my real tests inside the loop and set "done" appropriately, but I am curious as to 1) why the above does not work, and 2) is there some small correction that would make it work? I still fairly confused about when to use [, (, {, or ((, so perhaps some other combination would work, though I have tried several.

(Note: The "read -u 4 line" works fine when I call it above the loop. I have opened a file on file descriptor 4.)

Upvotes: 1

Views: 5204

Answers (2)

Jonathan
Jonathan

Reputation: 13614

I think what you want is more like this:

while read -u 4 line && test "$line" != "$header_line"
do
    ...
done

Braces (the {} characters) are used to separate variables from other parts of a string when whitespace cannot be used. For example, echo "${var}x" will print the value of the variable var followed by an x, but echo "$varx" will print the value of the variable varx.

Brackets (the [] characters) are used as a shortcut for the test program. [ is another name for test, but when test detects that it was called with [ it required a ] as its last argument. The point is clarity.

Parenthesis (the () characters) are used in a number of different situations. They generally start subshells, although not always (I'm not really certain in case #3 here):

  1. Retrieving a single exit code from a series of processes, or a single output stream from a sequence of commands. For example, (echo "Hi" ; echo "Bye") | sed -e "s/Hi/Hello/" will print two lines, "Hello" and "Bye". It is the easiest way to get multiple echo statements to produce a single stream.
  2. Evaluating commands as if they were variables: $(expr 1 + 1) will act like a variable, but will produce the value 2.
  3. Performing math: $((5 * 4 / 3 + 2 % 1)) will evaluate like a variable, but will compute the result of that mathematical expression.

Upvotes: 5

flolo
flolo

Reputation: 15486

The && operator is a list operator - he seperates two commands and only executes when the first is true, but in this case the first is the while and he is expecting his do stuff. And then he reaches do and the while stuff is already history. Your intention is to put it into the expression. So you put it together with (). E.g. this a solution with just a small change

while ( read -u 4 line  && test "$line" != "$header_line" )

Upvotes: 2

Related Questions