desarrollo-web-br-bd.com

¿Cuál es la diferencia entre los operadores Bash [[vs [vs (vs ((?

Estoy un poco confundido sobre qué hacen estos operadores de manera diferente cuando se usan en bash (corchetes, corchetes dobles, paréntesis y paréntesis dobles).

[[ , [ , ( , ((

He visto a personas usarlas en declaraciones if como esta:

if [[condition]]

if [condition]

if ((condition))

if (condition)
298
RetroCode

Una declaración if normalmente se ve así

if commands1
then
   commands2
else
   commands3
fi

La cláusula then se ejecuta si el código de salida de commands1 Es cero. Si el código de salida no es cero, se ejecuta la cláusula else. commands1 Puede ser simple o complejo. Puede, por ejemplo, ser una secuencia de una o más tuberías separadas por uno de los operadores ;, &, && O ||. Las condiciones if que se muestran a continuación son solo casos especiales de commands1:

  1. if [ condition ]

    Este es el comando tradicional Shell test. Está disponible en todos los shells POSIX. El comando de prueba establece un código de salida y la instrucción if actúa en consecuencia. Las pruebas típicas son si existe un archivo o si un número es igual a otro.

  2. if [[ condition ]]

    Esta es una nueva variación mejorada en test from ksh that bash y zsh también son compatibles. Este comando test también establece un código de salida y la instrucción if actúa en consecuencia. Entre sus características extendidas, puede probar si una cadena coincide con una expresión regular.

  3. if ((condition))

    Otra extensión ksh que bash y zsh también es compatible. Esto realiza aritmética. Como resultado de la aritmética, se establece un código de salida y la instrucción if actúa en consecuencia. Devuelve un código de salida de cero (verdadero) si el resultado del cálculo aritmético es distinto de cero. Al igual que [[...]], Este formulario no es POSIX y, por lo tanto, no es portátil.

  4. if (command)

    Esto ejecuta el comando en una subshell. Cuando se completa el comando, establece un código de salida y la instrucción if actúa en consecuencia.

    Una razón típica para usar un subshell como este es limitar los efectos secundarios de command si command requiere asignaciones variables u otros cambios en el entorno de Shell. Tales cambios no permanecen después de que se completa la subshell.

  5. if command

    el comando se ejecuta y la instrucción if actúa de acuerdo con su código de salida.

316
John1024
  • Los paréntesis (…) Indican un subshell . Lo que hay dentro de ellos no es una expresión como en muchos otros idiomas. Es una lista de comandos (al igual que los paréntesis externos). Estos comandos se ejecutan en un subproceso separado, por lo que cualquier redirección, asignación, etc. realizada dentro de los paréntesis no tiene efecto fuera de los paréntesis.
    • Con un signo de dólar inicial, $(…) es un sustitución de comando : hay un comando dentro de los paréntesis, y la salida del comando se usa como parte de la línea de comando (después de extra expansiones a menos que la sustitución sea entre comillas dobles, pero eso es otra historia ).
  • Las llaves { … } Son como paréntesis porque agrupan comandos, pero solo influyen en el análisis, no en la agrupación. El programa x=2; { x=4; }; echo $x Imprime 4, mientras que x=2; (x=4); echo $x imprime 2. (También se deben delimitar las llaves palabras clave y encontrado en la posición de comando (de ahí el espacio después de { y el ; antes de }) mientras que los paréntesis no. Eso es solo una peculiaridad de sintaxis.]
    • Con un signo de dólar inicial, ${VAR} Es un expansión de parámetros , expandiéndose al valor de una variable, con posibles transformaciones adicionales. El shell ksh93 También admite ${ cmd;} Como una forma de sustitución de comando que no genera un subshell.
  • ((…)) Paréntesis dobles rodean un instrucción aritmética , es decir, un cálculo en enteros, con una sintaxis similar a otros lenguajes de programación. Esta sintaxis se usa principalmente para asignaciones y en condicionales. Esto solo existe en ksh/bash/zsh, no en sh simple.
    • La misma sintaxis se usa en las expresiones aritméticas $((…)), que se expanden al valor entero de la expresión.
  • [ … ] Corchetes simples rodean expresiones condicionales . Las expresiones condicionales se basan principalmente en operadores como -n "$variable" Para probar si una variable está vacía y -e "$file" Para probar si existe un archivo. Tenga en cuenta que necesita un espacio alrededor de cada operador (por ejemplo, [ "$x" = "$y" ], No [ "$x"="$y" ]), y un espacio o un carácter como ; tanto dentro como fuera de los corchetes (por ejemplo, [ -n "$foo" ], no [-n "$foo"]).
  • [[ … ]] Los corchetes dobles son una forma alternativa de expresiones condicionales en ksh/bash/zsh con algunas características adicionales, por ejemplo, puede escribir [[ -L $file && -f $file ]] Para probar si un archivo es un enlace simbólico a un enlace regular archivo, mientras que los corchetes simples requieren [ -L "$file" ] && [ -f "$file" ]. Consulte ¿Por qué la expansión de parámetros con espacios sin comillas funciona entre corchetes [[pero no entre corchetes [? para obtener más información sobre este tema.

En el Shell, cada comando es un comando condicional: cada comando tiene un estado de retorno que es 0, que indica éxito o un número entero entre 1 y 255 (y potencialmente más en algunos proyectiles) que indica falla. El comando [ … ] (O la forma de sintaxis [[ … ]]) Es un comando particular que también se puede escribir test … Y tiene éxito cuando existe un archivo o cuando una cadena no está vacía, o cuando un número es más pequeño que otro, etc. La forma de sintaxis ((…)) tiene éxito cuando un número no es cero. Aquí hay algunos ejemplos de condicionales en un script de Shell:

  • Pruebe si myfile contiene la cadena hello:

    if grep -q hello myfile; then …
    
  • Si mydir es un directorio, cámbielo y haga cosas:

    if cd mydir; then
      echo "Creating mydir/myfile"
      echo 'some content' >myfile
    else
      echo >&2 "Fatal error. This script requires mydir to exist."
    fi
    
  • Pruebe si hay un archivo llamado myfile en el directorio actual:

    if [ -e myfile ]; then …
    
  • Lo mismo, pero también incluye enlaces simbólicos colgantes:

    if [ -e myfile ] || [ -L myfile ]; then …
    
  • Pruebe si el valor de x (que se supone que es numérico) es al menos 2, de forma portátil:

    if [ "$x" -ge 2 ]; then …
    
  • Pruebe si el valor de x (que se supone que es numérico) es al menos 2, en bash/ksh/zsh:

    if ((x >= 2)); then …
    

Del documentación bash :

(list) la lista se ejecuta en un entorno de subshell (ver ENTORNO DE EJECUCIÓN DE MANDOS a continuación) Las asignaciones variables y los comandos incorporados que afectan el entorno de Shell no permanecen vigentes una vez que se completa el comando. El estado de retorno es el estado de salida de la lista.

En otras palabras, se asegura de que lo que suceda en 'lista' (como un cd) no tenga ningún efecto fuera del ( y ). Lo único que se filtrará es el código de salida del último comando o con set -e el primer comando que genera un error (aparte de algunos como if, while, etc.)

((expression)) La expresión se evalúa de acuerdo con las reglas que se describen a continuación en EVALUACIÓN ARITMÉTICA. Si el valor de la expresión no es cero, el estado de retorno es 0; de lo contrario, el estado de retorno es 1. Esto es exactamente equivalente a dejar "expresión".

Esta es una extensión bash que te permite hacer matemáticas. Esto es algo similar a usar expr sin todas las limitaciones de expr (como tener espacios en todas partes, escapar *, etc.)

[[ expression ]] Devuelve un estado de 0 o 1 dependiendo de la evaluación de la expresión de expresión condicional. Las expresiones se componen de las primarias que se describen a continuación en EXPRESIONES CONDICIONALES. La división de palabras y la expansión del nombre de ruta no se realizan en las palabras entre [[y]]; Se realiza la expansión de tilde, la expansión de parámetros y variables, la expansión aritmética, la sustitución de comandos, la sustitución de procesos y la eliminación de comillas. Los operadores condicionales como -f deben estar sin comillas para ser reconocidos como primarios.

Cuando se usa con [[ los operadores <y> se ordenan lexicográficamente usando la localización actual.

Esto ofrece una prueba avanzada para comparar cadenas, números y archivos un poco como test ofertas, pero más potente.

[ expr ] Devuelve un estado de 0 (verdadero) o 1 (falso) dependiendo de la evaluación de la expresión condicional expr. Cada operador y operación y debe ser un argumento separado. Las expresiones se componen de las primarias descritas anteriormente en EXPRESIONES CONDICIONALES. test no acepta ninguna opción, ni acepta e ignora un argumento de - como significa el final de las opciones.

[...]

Este llama a test. En realidad, en los viejos tiempos, [ era un enlace simbólico a test. Funciona de la misma manera y tienes las mismas limitaciones. Como un binario conoce el nombre con el que se inició, el programa de prueba puede analizar los parámetros hasta que encuentre un parámetro ]. Divertidos trucos de Unix.

Tenga en cuenta que en el caso de bash, [ y test son funciones integradas (como se menciona en un comentario), pero se aplican casi las mismas limitaciones.

20
Alexis Wilke

[ Vs [[

Esta respuesta cubrirá el subconjunto [ Vs [[ De la pregunta.

Algunas diferencias en Bash 4.3.11:

  • Extensión POSIX vs Bash:

  • comando regular vs magia

    • [ Es solo un comando regular con un nombre extraño.

      ] Es solo un argumento de [ Que evita que se utilicen más argumentos.

      Ubuntu 16.04 en realidad tiene un ejecutable para él en /usr/bin/[ Proporcionado por coreutils, pero la versión incorporada de bash tiene prioridad.

      Nada se altera en la forma en que Bash analiza el comando.

      En particular, < Es redirección, && Y || Concatenan múltiples comandos, ( ) Genera subshells a menos que \ Y la expansión de Word escapen sucede como siempre.

    • [[ X ]] Es una construcción única que hace que X se analice mágicamente. <, &&, || Y () Se tratan especialmente, y las reglas de división de Word son diferentes.

      También hay más diferencias como = Y =~.

      En Bashese: [ Es un comando incorporado, y [[ Es una palabra clave: https://askubuntu.com/questions/445749/whats-the-difference-between -Shell-builtin-and-Shell-keyword

  • <

  • && Y ||

    • [[ a = a && b = b ]]: Verdadero, lógico y
    • [ a = a && b = b ]: Error de sintaxis, && Analizado como un separador de comando AND cmd1 && cmd2
    • [ a = a -a b = b ]: Equivalente, pero obsoleto por POSIX³
    • [ a = a ] && [ b = b ]: POSIX y equivalente confiable
  • (

    • [[ (a = a || a = b) && a = b ]]: falso
    • [ ( a = a ) ]: error de sintaxis, () se interpreta como una subshell
    • [ \( a = a -o a = b \) -a a = b ]: equivalente, pero () está en desuso por POSIX
    • { [ a = a ] || [ a = b ]; } && [ a = b ] POSIX equivalente5 5
  • División de palabras y generación de nombre de archivo en expansiones (división + glob)

    • x='a b'; [[ $x = 'a b' ]]: Verdadero, no se necesitan comillas
    • x='a b'; [ $x = 'a b' ]: Error de sintaxis, se expande a [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]: Error de sintaxis si hay más de un archivo en el directorio actual.
    • x='a b'; [ "$x" = 'a b' ]: Equivalente POSIX
  • =

    • [[ ab = a? ]]: Verdadero, porque lo hace coincidencia de patrones (* ? [ Son mágicos). No se expande globalmente a los archivos en el directorio actual.
    • [ ab = a? ]: a? El globo se expande. Por lo tanto, puede ser verdadero o falso dependiendo de los archivos en el directorio actual.
    • [ ab = a\? ]: Falso, no expansión global
    • = Y == Son iguales en [ Y [[, Pero == Es una extensión Bash.
    • case ab in (a?) echo match; esac: equivalente POSIX
    • [[ ab =~ 'ab?' ]]: Falso4 4, pierde magia con ''
    • [[ ab? =~ 'ab?' ]]: Verdadero
  • =~

    • [[ ab =~ ab? ]]: Verdadero, POSIX expresión regular extendida coincidencia, ? No se expande globalmente
    • [ a =~ a ]: Error de sintaxis. No hay bash equivalente.
    • printf 'ab\n' | grep -Eq 'ab?': Equivalente a POSIX (solo datos de una línea)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': equivalente POSIX.

Recomendación : siempre use [].

Hay equivalentes POSIX para cada construcción [[ ]] Que he visto.

Si usa [[ ]] Usted:

  • perder portabilidad
  • obligar al lector a aprender las complejidades de otra extensión bash. [ Es solo un comando regular con un nombre extraño, no hay una semántica especial involucrada.

¹ Inspirado en la construcción equivalente [[...]] En Korn Shell

² pero falla para algunos valores de a o b (como + O index) y hace una comparación numérica si a y b parecen enteros decimales. expr "x$a" '<' "x$b" Funciona alrededor de ambos.

³ y también falla para algunos valores de a o b como ! O (.

4 4 en bash 3.2 y superior y la compatibilidad proporcionada a bash 3.1 no está habilitada (como con BASH_COMPAT=3.1)

5 5 aunque la agrupación (¡aquí con el grupo de comando {...;} en lugar de (...) que ejecutaría una subshell innecesaria) no es necesaria ya que los operadores Shell || y && (a diferencia de los operadores || y &&[[...]] o los operadores -o/-a[ tienen los mismos precedencia. Entonces [ a = a ] || [ a = b ] && [ a = b ] Sería equivalente.

Algunos ejemplos:

Prueba tradicional:

foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then... 
if test -n "$foo" ; then... 

test y [ son comandos como cualquier otro, por lo que la variable se divide en palabras a menos que esté entre comillas.

Prueba de nuevo estilo

[[ ... ]] es una construcción de Shell especial (más nueva), que funciona de manera un poco diferente, lo más obvio es que no tiene variables divididas en Word:

if [[ -n $foo ]] ; then... 

Algunos documentación sobre [ y [[ aquí .

Prueba aritmética:

foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...  

Comandos "normales":

Todo lo anterior actúa como comandos normales, y if puede tomar cualquier comando:

# grep returns true if it finds something
if grep pattern file ; then ...

Múltiples comandos:

O podemos usar múltiples comandos. Envolviendo un conjunto de comandos en ( ... ) los ejecuta en subshell, creando una copia temporal del estado del Shell (directorio de trabajo, variables). Si necesitamos ejecutar algún programa temporalmente en otro directorio:

# this will move to $somedir only for the duration of the subshell 
if ( cd $somedir ; some_test ) ; then ...

# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...
13
ilkkachu

Comandos de agrupamiento

Bash proporciona dos formas de agrupar una lista de comandos que se ejecutarán como una unidad.

( list ) Al colocar una lista de comandos entre paréntesis, se crea un entorno de subshell y cada uno de los comandos de la lista se ejecuta en esa subshell. Dado que la lista se ejecuta en una subshell, las asignaciones de variables no permanecerán vigentes una vez que se complete la subshell.

$ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a"
inside: a=2
outside: a=1

{ list; } Colocar una lista de comandos entre llaves hace que la lista se ejecute en el contexto actual de Shell . No se crea ninguna subshell. Se requiere la siguiente lista de punto y coma (o nueva línea). Fuente

${} Parameter expansion Ex:  ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s
$() Command substitution Ex: result=$(COMMAND) 
$(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

Construcciones condicionales

Soporte simple es decir []
Para comparacion ==, !=, <, y > y debe usarse y para la comparación numérica eq, ne,lt y gt deben usarse.

Corchetes mejorados es decir [[]]

En todos los ejemplos anteriores, utilizamos solo corchetes para encerrar la expresión condicional, pero bash permite corchetes dobles que sirve como una versión mejorada de la sintaxis de un solo corchete.

Para comparacion ==, !=, <, y > puede usar literalmente.

  • [ es sinónimo de comando de prueba. Incluso si está integrado en el Shell, crea un nuevo proceso.
  • [[ es una nueva versión mejorada de la misma, que es una palabra clave, no un programa.
  • [[ se entiende por Korn y Bash.

Fuente

1
Premraj