103

This question is a sequel of sorts to my earlier question. The users on this site kindly helped me determine how to write a bash for loop that iterates over string values. For example, suppose that a loop control variable fname iterates over the strings "a.txt" "b.txt" "c.txt". I would like to echo "yes!" when fname has the value "a.txt" or "c.txt", and echo "no!" otherwise. I have tried the following bash shell script:

#!/bin/bash

for fname in "a.txt" "b.txt" "c.txt"
do
 echo $fname
 if [ "$fname" = "a.txt" ] | [ "$fname" = "c.txt" ]; then
 echo "yes!"
else
 echo "no!"
fi
done

I obtain the output:

a.txt

no!

b.txt

no!

c.txt

yes!

Why does the if statement apparently yield true when fname has the value "a.txt"? Have I used | incorrectly?

  • 3
    In bash, 'or' operator is '||' (C style). – Marius Cotofana Sep 8 '12 at 20:47
  • 3
    You can also use -o within the same [ ]. – Thor Sep 8 '12 at 20:53
  • 6
    @Thor I'd prefer || and separate [ ] over -o for portability simply because [ is not guaranteed to support more than 4 arguments. Of course if the target language is bash, no one should be using [ anyways because bash's [[ is superior in many ways. – jw013 Sep 9 '12 at 0:46
  • 1
    @jw013 Thanks. Does this mean that I should be using if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]] rather than if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]? – Andrew Sep 9 '12 at 17:14
  • 5
    @Andrew That is correct, if as you are declaring the shebang as bash, as you are already doing. One advantage of [[ is that it doesn't do word splitting (special case) so [[ $unquoted_var = string ]] is safe. – jw013 Sep 10 '12 at 2:06
181

If you want to say OR use double pipe (||).

if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]

(The original OP code using | was simply piping the output of the left side to the right side, in the same way any ordinary pipe works.)

  • 4
    Furthermore, || doesn't do a standard logic "OR" - it short-circuits, and the second command is run only if the first fails. – holdenweb Dec 12 '16 at 19:33
  • 10
    @holdenweb I'm pretty sure most modern optimized languages work the same way. No need to spend CPU cycles evaluating the second condition of OR if the first condition evaluates true. – bahamat Dec 12 '16 at 20:50
  • 1
    I thought bash liked == but after seeing this answer, I decided to look it up. Apparently, "it can be used but isn't standard". I thought I'd put this here for others if your curious: stackoverflow.com/a/2237103 – harperville Sep 17 '18 at 15:55
  • This is what the test man page recommends too – cdosborn Apr 21 at 18:13
  • 1
    You can also use double bracket tests - if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]] (If you want or need to have the extra functionality associated with [[ ]]). – HankCa Apr 24 at 5:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.