En un script bash, usando el condicional "o" en una declaración "if"

129

Esta pregunta es una secuela de mi pregunta anterior . Los usuarios de este sitio amablemente me ayudaron a determinar cómo escribir un forbucle bash que itera sobre valores de cadena. Por ejemplo, suponga que una variable de control de bucle fnameitera sobre las cadenas "a.txt" "b.txt" "c.txt". Me gustaría echo"¡sí!" cuando fnametiene el valor "a.txt"o "c.txt", y echo"no!" de otra manera. He intentado el siguiente script de bash shell:

#!/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

Obtengo la salida:

a.txt

¡No!

b.txt

¡No!

c.txt

¡si!

¿Por qué la ifafirmación aparentemente es verdadera cuando fnametiene el valor "a.txt"? ¿Lo he usado |incorrectamente?

Andrés
fuente
3
En bash, 'u' operador es '||' (Estilo C).
Marius Cotofana
3
También se puede usar -odentro del mismo [ ].
Thor
66
@Thor preferiría ||y separar [ ]más -opara la portabilidad, simplemente porque [no está garantizada para soportar más de 4 argumentos. Por supuesto, si el idioma de destino es bash, nadie debería usarlo de [todos modos porque bashel [[es superior en muchos aspectos.
jw013
2
@ jw013 Gracias. ¿Esto significa que debería estar usando en if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]]lugar de if [ "$fname" = "a.txt" ] || [ "$fname" = "c.txt" ]?
Andrew
55
@ Andrew Eso es correcto, si como estás declarando el shebang como bash, como ya lo estás haciendo. Una ventaja de esto [[es que no divide las palabras (caso especial), por lo que [[ $unquoted_var = string ]]es seguro.
jw013

Respuestas:

229

Si quieres decir ORusa double pipe ( ||).

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

(El código OP original que se usaba |era simplemente canalizar la salida del lado izquierdo al lado derecho, de la misma manera que funciona cualquier tubería normal).

bahamat
fuente
44
Además, ||no hace una lógica estándar "OR": hace un cortocircuito y el segundo comando se ejecuta solo si el primero falla.
holdenweb
13
@holdenweb Estoy bastante seguro de que los lenguajes optimizados más modernos funcionan de la misma manera. No es necesario gastar ciclos de CPU evaluando la segunda condición de ORsi la primera condición se evalúa como verdadera.
bahamat
1
Pensé que le gustaba a bash, ==pero después de ver esta respuesta, decidí buscarla. Aparentemente, "se puede usar pero no es estándar". Pensé que pondría esto aquí para otros si tienes curiosidad: stackoverflow.com/a/2237103
harperville
Esto es lo testque también recomienda la página de
manual
2
También puede usar pruebas de doble parche if [[ "$fname" = "a.txt" ]] || [[ "$fname" = "c.txt" ]](si desea o necesita tener la funcionalidad adicional asociada [[ ]]).
HankCa