Veo que puedo hacer
$ [ -w /home/durrantm ] && echo "writable"
writable
o
$ test -w /home/durrantm && echo "writable"
writable
o
$ [[ -w /home/durrantm ]] && echo "writable"
writable
Me gusta usar la tercera sintaxis. ¿Son equivalentes en todos los sentidos y para todos los casos negativos y extremos? ¿Hay alguna diferencia en la portabilidad, por ejemplo, entre bash en Ubuntu y en OS X o versiones anteriores / posteriores de bash, por ejemplo, antes / después de 4.0 y ambas expanden las expresiones de la misma manera?
shell
posix
test
portability
Michael Durrant
fuente
fuente
[ … ]
vs[[ … ]]
vstest …
, hay respuestas más completas en esta pregunta mayormente duplicada .Respuestas:
[
es sinónimo deltest
comando y es simultáneamente un comando bash incorporado y un comando separado. Pero[[
es una palabra clave bash y funciona solo en algunas versiones. Entonces, por razones de portabilidad, es mejor usar solo[]
otest
fuente
[
¿Está POSIX integrado o Bash integrado?test
y[
por igual. Si un shell puede hacer la evaluación por sí solo, eso le ahorra un proceso y lo hace algo más rápido, pero el resultado tiene que ser el mismo.[
está definido por POSIX y, por lo tanto, es máximamente portátil (que parece ser el punto central de esta pregunta si no me equivoco)[
ytest
son POSIX . Parece no haber ninguno "recomendado", aunque la única diferencia (?) Que puedo detectar entre ellos es quetest
"no reconocerá el argumento" - "[como un delimitador que indica el final de las opciones]" (? - lo que implica que " - " es reconocido como el fin de los argumentos[
, para lo cual no puedo encontrar un buen caso de prueba de todos modos. Pero estoy divagando. Usa lo que quieras. OMI, se[
ve elegante, pero estest
claramente un comando)Si, hay diferencias. Los más portátiles son
test
o[ ]
. Ambos son parte de la especificación POSIXtest
.La
if ... fi
construcción también está definida por POSIX y debe ser completamente portátil.Esta
[[ ]]
es unaksh
característica que también está presente en algunas versiones debash
( todas las modernas ), enzsh
y tal vez en otras, pero no está presente ensh
o endash
varios otros shells más simples.Por lo tanto, para hacer sus guiones portátil, usar
[ ]
,test
oif ... fi
.fuente
bash
y lozsh
he apoyado[[
durante mucho tiempo (lobash
agregué a fines de los 90, azsh
más tardar en el 2000, y me sorprendería si alguna vez careció de soporte), por lo que es poco probable que encuentre una versión de cualquiera de los dos[[
. Encontrar un shell diferente compatible con POSIX (comodash
) es mucho más probable.[[
es que no es necesario citar las expansiones de parámetros: el[[-f $file]]
evento funciona si$file
contiene caracteres de espacio en blanco.[[ $a =~ ^reg.*exp.*$' ]]
Tenga en cuenta que eso
[] && cmd
no es lo mismo que laif .. fi
construcción.A veces su comportamiento es bastante similar y puedes usarlo en
[] && cmd
lugar deif .. fi
. Pero solo a veces. Si tiene más de un comando para ejecutar si la condición o necesitaif .. else .. fi
tener cuidado y cambiar la lógica.Un par de ejemplos:
No es lo mismo que
porque si
ls
falla,echo
se ejecutará, lo que no sucederá conif
.Otro ejemplo:
no es lo mismo que
aunque esta construcción actuará igual
tenga en cuenta que
;
después del eco es importante y debe estar allí.Entonces, resumiendo la declaración anterior, podemos decir
[] && cmd
== si el primer comando es exitoso, ejecute el siguienteif .. fi
== si la condición (que también puede ser el comando de prueba), entonces ejecute los comandosPor lo tanto, para la portabilidad
[
y el[[
uso[
solo.if
es POSIX compatible. Entonces, si tiene que elegir[
yif
elegir mirar su tarea y el comportamiento esperado.fuente
[ -z "$VAR" ] && { ls file; true; } || echo wiiii
. Es un poco más detallado, pero aún es más corto que laif...fi
construcción.[
yif
como substitutos, pero no lo son. En realidad, es lo&&
que está reemplazando alif
.[
ejecuta un código y devuelve un estado, al igual quels
ygrep
would.if
La ejecución de las ramas depende del estado de retorno del comando (instrucción) dado después del if, podría ser cualquier comando (instrucción).&&
ejecuta la siguiente declaración solo si la anterior devolvió 0, de forma muy similar a una simpleif..then..fi
.En realidad,
&&
es lo que está reemplazando elif
, no eltest
: unaif
declaración en las secuencias de comandos de shell prueba si un comando devolvió un estado de salida "exitoso" (cero); en su ejemplo, el comando es[
.Entonces, en realidad hay dos cosas que está variando aquí: el comando utilizado para ejecutar la prueba y la sintaxis utilizada para ejecutar el código en función del resultado de esa prueba.
Comandos de prueba:
test
es un comando estandarizado para evaluar las propiedades de cadenas y archivos; en su ejemplo, está ejecutando el comandotest -w /home/durrantm
[
es un alias de ese comando, igualmente estandarizado, que tiene un último argumento obligatorio]
para parecer una expresión entre corchetes; no se deje engañar, sigue siendo solo un comando (incluso puede encontrar que su sistema tiene un archivo llamado/bin/[
)[[
es una versión extendida del comando de prueba integrado en algunos shells, pero no forma parte del mismo estándar POSIX; incluye opciones adicionales que no estás usando aquíExpresiones condicionales:
&&
operador ( estandarizado aquí ) realiza una operación AND lógica, evaluando dos comandos y devolviendo 0 (que representa verdadero) si ambos devuelven 0; solo evaluará el segundo comando si el primero devuelve cero, por lo que puede usarse como un simple condicionalif ... then ... fi
constructo ( estandarizado aquí ) utiliza el mismo método para juzgar la "verdad", pero permite una lista compuesta de declaraciones en lathen
cláusula, en lugar del comando único proporcionado por un&&
cortocircuito, y proporcionaelif
yelse
cláusulas, que son difíciles de escribir utilizando solo&&
y||
. Tenga en cuenta que no hay corchetes alrededor de la condición en unaif
declaración .Por lo tanto, las siguientes son representaciones de su ejemplo igualmente portátiles y totalmente equivalentes:
test -w /home/durrantm && echo "writable"
[ -w /home/durrantm ] && echo "writable"
if test -w /home/durrantm; then echo "writable"; fi
if [ -w /home/durrantm ]; then echo "writable"; fi
Si bien los siguientes también son equivalentes, pero menos portátiles debido a la naturaleza no estándar de
[[
:[[ -w /home/durrantm ]] && echo "writable"
if [[ -w /home/durrantm ]]; then echo "writable"; fi
fuente
Para portabilidad, use
test
/[
. Pero si no necesita la portabilidad, por el bien de usted mismo y de otros que leen su script, use[[
. :)Ver también
What is the difference between test, [ and [[ ?
en BashFAQ .fuente
Si desea portabilidad fuera del mundo tipo Bourne, entonces:
Es el más portátil. Funciona en conchas del Bourne,
csh
yrc
familias.salida sería
"writable"
en lugar dewritable
en los depósitos de larc
familia (rc
,es
,akanga
, donde"
no es especial).no funcionaría en shells de
csh
orc
familias en sistemas que no tienen un[
comando$PATH
(se sabe que algunos tienentest
pero no su[
alias).solo funciona en conchas de la familia Bourne.
solo funciona en
ksh
(donde se originó)zsh
ybash
(los 3 en la familia Bourne).Ninguno funcionaría en el
fish
shell donde necesita:o:
fuente
Mi razón más importante para elegir
if foo; then bar; fi
ofoo && bar
es si el estado de salida de todo el comando es importante.comparar:
con:
Se podría pensar que hacen lo mismo; sin embargo, si
foo
falla (o es falso, dependiendo de su punto de vista), en el primer ejemplo, do_baz no se ejecutará, ya que el script habrá salido ... Leset -e
indica al shell que salga inmediatamente si algún comando devuelve un estado falso. Muy útil si estás haciendo cosas como:No desea que el script continúe ejecutándose si
cd
falla por alguna razón.fuente
foo
no abortará el script en ninguno de los casos. Eso es un caso especial paraset -e
(cuando el comando se evalúa como una condición (a la izquierda de algunos && / || o si /, mientras que / hasta / elsif ... condiciones) Una falla.bar
Podría salir de la cáscara en ambos casos.cd /some/directory && rm -rf -- *
ocd /some/directory || exit; rm -rf -- *
(aún no elimina los archivos ocultos). Personalmente no me gusta la idea de usarset -e
como excusa para no hacer un esfuerzo para escribir el código correcto.