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 deltestcomando 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[]otestfuente
[¿Está POSIX integrado o Bash integrado?testy[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)[ytestson 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 estestclaramente un comando)Si, hay diferencias. Los más portátiles son
testo[ ]. Ambos son parte de la especificación POSIXtest.La
if ... ficonstrucción también está definida por POSIX y debe ser completamente portátil.Esta
[[ ]]es unakshcaracterística que también está presente en algunas versiones debash( todas las modernas ), enzshy tal vez en otras, pero no está presente ensho endashvarios otros shells más simples.Por lo tanto, para hacer sus guiones portátil, usar
[ ],testoif ... fi.fuente
bashy lozshhe apoyado[[durante mucho tiempo (lobashagregué a fines de los 90, azshmá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$filecontiene caracteres de espacio en blanco.[[ $a =~ ^reg.*exp.*$' ]]Tenga en cuenta que eso
[] && cmdno es lo mismo que laif .. ficonstrucción.A veces su comportamiento es bastante similar y puedes usarlo en
[] && cmdlugar deif .. fi. Pero solo a veces. Si tiene más de un comando para ejecutar si la condición o necesitaif .. else .. fitener cuidado y cambiar la lógica.Un par de ejemplos:
No es lo mismo que
porque si
lsfalla,echose 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.ifes POSIX compatible. Entonces, si tiene que elegir[yifelegir 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...ficonstrucción.[yifcomo substitutos, pero no lo son. En realidad, es lo&&que está reemplazando alif.[ejecuta un código y devuelve un estado, al igual quelsygrepwould.ifLa 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: unaifdeclaració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:
testes 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 ... ficonstructo ( estandarizado aquí ) utiliza el mismo método para juzgar la "verdad", pero permite una lista compuesta de declaraciones en lathencláusula, en lugar del comando único proporcionado por un&&cortocircuito, y proporcionaelifyelsecláusulas, que son difíciles de escribir utilizando solo&&y||. Tenga en cuenta que no hay corchetes alrededor de la condición en unaifdeclaració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"; fiif [ -w /home/durrantm ]; then echo "writable"; fiSi 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"; fifuente
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,
cshyrcfamilias.salida sería
"writable"en lugar dewritableen los depósitos de larcfamilia (rc,es,akanga, donde"no es especial).no funcionaría en shells de
cshorcfamilias en sistemas que no tienen un[comando$PATH(se sabe que algunos tienentestpero no su[alias).solo funciona en conchas de la familia Bourne.
solo funciona en
ksh(donde se originó)zshybash(los 3 en la familia Bourne).Ninguno funcionaría en el
fishshell donde necesita:o:
fuente
Mi razón más importante para elegir
if foo; then bar; fiofoo && bares si el estado de salida de todo el comando es importante.comparar:
con:
Se podría pensar que hacen lo mismo; sin embargo, si
foofalla (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 -eindica 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
cdfalla por alguna razón.fuente
foono 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.barPodrí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 -ecomo excusa para no hacer un esfuerzo para escribir el código correcto.