Mert Nuhoglu
Mert Nuhoglu

Reputation: 10133

What does && do in redirecting an output to a file?

I found a bash script that lists all files with a blank line at the beginning or end of the file.

for f in `find . -type f`; do 
  for t in head tail; do 
    $t -1 $f  |egrep '^[  ]*$' >/dev/null && echo "blank line at the $t of $f" ;
  done; 
done

I would like to pass the output to a file. I changed the echo line to:

$t -1 $f  |egrep '^[  ]*$' >/dev/null && echo "blank line at the $t of $f" > blank_lines.log

But this didn't work.

I would like to ask what the symbol && does and why the above line does not pass the output to the file.

Upvotes: 2

Views: 2502

Answers (4)

Kaz Dragon
Kaz Dragon

Reputation: 6809

It's a short-circuited 'and' operator. It takes no part in output redirection.

In this context, it performs the right hand side only if the left hand side succeeded. I.e. it only prints out 'blank line at the ...' if there was indeed a blank line reported by egrep.

Upvotes: 3

Gordon Davisson
Gordon Davisson

Reputation: 125708

The reason the redirect doesn't work is that you used > to redirect output. This erases the file before writing the command's output to it, meaning that you'll only ever see the last thing written to it. To fix this, either use >> to append (although you may need to truncate the file at the beginning to prevent the output from multiple runs of the script accumulating), or redirect output for the entire loop.

BTW, the for ... find construct you're using to iterate over files will fail horribly if any filenames have spaces or other funny characters in them. It's much better to use find ... -print0 | while IFS= read -d $'\0' ... (and then use double-quotes around $f):

find . -type f -print0 | while IFS= read -d $'\0' f; do 
    for t in head tail; do 
        $t -1 "$f"  |egrep '^[  ]*$' >/dev/null && echo "blank line at the $t of $f"
    done
done > blank_lines.log

Upvotes: 3

Dani Gehtdichnixan
Dani Gehtdichnixan

Reputation: 1285

As mentioned by the other guys && is a short-circuited and operator:

command1 && command2

executes command1 and, if that command did run without errors (exit code 0) executes command2. It then returns the exit code of command2.

echo "foo" > /dev/null && echo "bar" > tmp.txt

does work, so the reason your script does not work should be something else. Perhaps try executing the

$t -1 $f  |egrep '^[  ]*$' >/dev/null && echo "blank line at the $t of $f" > blank_lines.log

line without the variables and the for loop.

Upvotes: 2

Ivaylo Strandjev
Ivaylo Strandjev

Reputation: 70931

This does not redirect output it adds another command to execute if and only if the first one succeeded. I.e command1 && command2 means execute command1 and if it is successful execute command2. Also the result of executing this statement is success if and only if both commands succeeded.

Upvotes: 5

Related Questions