180

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
  • 4
    You can also use -o within the same [ ]. – Thor Sep 8 '12 at 20:53
  • 8
    @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
  • 2
    @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
308

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.)

|improve this answer|||||
  • 6
    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
  • 16
    @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 '19 at 18:13
  • 3
    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 '19 at 5:45
17

The accepted answer is good but since you're using bash I'll add the bash solution:

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

This is documented in the bash reference manual 3.2.4.2 Conditional Constructs

expression1 && expression2

True if both expression1 and expression2 are true.

expression1 || expression2

True if either expression1 or expression2 is true.

The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.

|improve this answer|||||
0

You can use or condition like this

 if [ "$fname" = "a.txt" -o "$fname" = "c.txt" ]
|improve this answer|||||
-1

How about something like:

if [ a = b ] || [ c = d && e = f]

Syntax can be tricky...

|improve this answer|||||
  • 1
    Syntax can be tricky, indeed. Do consider revisiting this answer to fix the syntax errors (spacing). Also consider testing it with variables containing spaces rather than just using static strings ([ a = b ] in your code would always be false, for example). – Kusalananda Mar 5 at 7:09

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.