In a bash script, using the conditional "or" in an "if" statement
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
forloop that iterates over string values. For example, suppose that a loop control variable
fnameiterates over the strings
"a.txt" "b.txt" "c.txt". I would like to
fnamehas the value
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:
Why does the
ifstatement apparently yield true when
fnamehas the value
"a.txt"? Have I used
@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 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 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.
`The XSI extensions specifying the -a and -o binary primaries and the '(' and ')' operators have been marked obsolescent.` and should not be used.
One huge disadvantage of `[[` (IMO, a complete show stopper) is that it does not produce reasonable error messages, but happily returns truthiness with no error message to statements like `[[ $a -eq 0 ]]` when $a is not an integer value. In other words, if the target language is bash, no one should be using `[[` at all.
If you want to say
ORuse 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.)
Furthermore, `||` doesn't do a standard logic "OR" - it short-circuits, and the second command is run only if the first fails.
@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.
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: https://stackoverflow.com/a/2237103
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 `[[ ]]`).
@bahamat, you should use `=` instead of `==` in `[...]`, it's the standard comparison operator. Bash does support `==` too, but not all shells do.
There is no need to wrap every expression in brackets which is slower in addition to adding more clutter.
I think @AnandShanbhag answer is better than this: https://unix.stackexchange.com/questions/47584/in-a-bash-script-using-the-conditional-or-in-an-if-statement/586897#586897