Control de flujo
Sentencia if
En shell scripting (Bash y similares), los comandos if
, else
, elif
, junto con los operadores lógicos (and
, or
, not
), se utilizan para implementar estructuras de control de flujo. El comando exit
se usa para finalizar un script o un proceso con un código de salida. A continuación, te explico cómo funcionan:
1. Condicionales (if
, else
, elif
):
Los condicionales se usan para ejecutar bloques de código dependiendo de si una condición es verdadera o falsa.
Sintaxis básica:
if [ condición ]; then
# Código a ejecutar si la condición es verdadera
elif [ otra_condición ]; then
# Código a ejecutar si la otra condición es verdadera
else
# Código a ejecutar si ninguna condición es verdadera
fi
Ejemplo:
#!/bin/bash
num=10
if [ $num -gt 5 ]; then
echo "El número es mayor que 5"
elif [ $num -eq 5 ]; then
echo "El número es igual a 5"
else
echo "El número es menor que 5"
fi
2. Operadores lógicos (and
, or
, not
):
En Bash, los operadores lógicos no se escriben directamente como and
, or
, o not
. En su lugar, usamos:
Operador | Símbolo | Descripción |
---|---|---|
AND | && | Ambas condiciones deben ser verdaderas. |
OR | ` | |
NOT | ! | Niega una condición. |
Ejemplo con AND y OR:
#!/bin/bash
a=10
b=20
if [ $a -gt 5 ] && [ $b -gt 15 ]; then
echo "Ambas condiciones son verdaderas"
elif [ $a -gt 5 ] || [ $b -lt 15 ]; then
echo "Al menos una condición es verdadera"
else
echo "Ninguna condición es verdadera"
fi
Ejemplo con NOT:
#!/bin/bash
a=5
if ! [ $a -eq 10 ]; then
echo "El valor de a no es 10"
fi
3. El comando exit
:
El comando exit
se utiliza para terminar un script o un proceso con un código de salida. Un código de salida:
0
significa que el script se ejecutó con éxito.- Cualquier otro número (por convención,
1-255
) indica un error o estado específico.
Ejemplo básico:
#!/bin/bash
if [ $# -eq 0 ]; then
echo "No se pasaron argumentos"
exit 1 # Termina el script con un código de error
fi
echo "Argumentos recibidos: $@"
exit 0 # Termina con éxito
Cuando ejecutas un script, puedes pasarle argumentos desde la línea de comandos. $# te indica cuántos de esos argumentos se pasaron.
Resumen del flujo:
Un ejemplo más completo:
#!/bin/bash
read -p "Introduce un número: " num
if [ $num -gt 10 ]; then
echo "El número es mayor que 10"
elif [ $num -eq 10 ]; then
echo "El número es igual a 10"
else
echo "El número es menor que 10"
fi
if [ $num -gt 5 ] && ! [ $num -eq 7 ]; then
echo "El número es mayor que 5 pero no es 7"
fi
exit 0 # Salida exitosa
Variable especial $?
En Bash scripting, $?
es una variable especial que contiene el código de salida del último comando o script que se ejecutó.
¿Qué es el código de salida?
- 0: Indica que el comando o script anterior se ejecutó correctamente (éxito).
- Cualquier otro valor: Indica que hubo un error o estado específico. Por convención:
- Valores positivos (como
1
,2
, etc.) indican errores o condiciones específicas. - Los valores exactos dependen del comando que se ejecutó.
- Valores positivos (como
Uso básico de $?
:
-
Después de un comando:
ls /ruta/valida echo "Código de salida: $?" ls /ruta/inexistente echo "Código de salida: $?"
Salida:
Código de salida: 0 # La primera ejecución de `ls` fue exitosa. Código de salida: 2 # La ruta no existe, por lo tanto, `ls` falló.
-
En un script:
#!/bin/bash mkdir nueva_carpeta if [ $? -eq 0 ]; then echo "Carpeta creada con éxito." else echo "Error al crear la carpeta." fi
Cómo utilizar $?
en diferentes escenarios:
1. Verificar el éxito de un comando:
cp archivo.txt /directorio/
if [ $? -eq 0 ]; then
echo "Archivo copiado correctamente."
else
echo "Error al copiar el archivo."
fi
2. Condicionales encadenados:
comando_1
if [ $? -ne 0 ]; then
echo "comando_1 falló, terminando el script."
exit 1
fi
comando_2
echo "comando_2 ejecutado correctamente."
Combinación con exit
:
Puedes usar $?
para devolver el estado de salida de un comando dentro de un script.
Ejemplo:
#!/bin/bash
ls /directorio/inexistente
exit $? # El script devolverá el código de salida del comando anterior.
Ejecución:
$ bash mi_script.sh
$ echo $?
2 # El código de salida de `ls` se propagó al script.
Ejemplo completo:
#!/bin/bash
echo "Probando comandos:"
mkdir carpeta_test
if [ $? -eq 0 ]; then
echo "Se creó la carpeta correctamente."
else
echo "Error al crear la carpeta."
fi
rm -r carpeta_test
if [ $? -eq 0 ]; then
echo "Se eliminó la carpeta correctamente."
else
echo "Error al eliminar la carpeta."
fi
Resumen:
$?
es útil para verificar el resultado de comandos y scripts.- Es especialmente importante en scripts automatizados para manejar errores y asegurarte de que las operaciones se ejecuten como esperas. ¡Te da control total sobre el flujo del script! 🎯
Explicación del Comando test
y el Uso de []
en Shell Script
En Shell Script, el comando test
y los corchetes []
son herramientas fundamentales para realizar evaluaciones de condiciones, como verificar si un archivo existe, comparar números, o evaluar cadenas de texto.
¿Qué es test
?
test
es un comando interno del shell que evalúa una condición y devuelve un código de salida:
- 0 (verdadero) si la condición se cumple.
- 1 (falso) si no se cumple.
Sintaxis básica:
test EXPRESIÓN
Por ejemplo:
test -f archivo.txt
Esto verifica si archivo.txt
existe y es un archivo regular.
¿Qué son los corchetes []
?
Los corchetes []
son una sintaxis simplificada de test
. Internamente, [ EXPRESIÓN ]
es equivalente a test EXPRESIÓN
. Sin embargo, hay que dejar un espacio entre los corchetes y la expresión.
Sintaxis básica:
[ EXPRESIÓN ]
Por ejemplo:
[ -f archivo.txt ]
Hace lo mismo que test -f archivo.txt
.
Casos de uso comunes
1. Evaluar cadenas de texto
-
Verificar si una cadena no está vacía:
[ -n "$cadena" ] && echo "No está vacía"
Equivalente a:
test -n "$cadena" && echo "No está vacía"
-
Verificar si dos cadenas son iguales:
[ "$cadena1" = "$cadena2" ] && echo "Son iguales"
2. Comparar números
-
Comparar si un número es mayor que otro:
[ "$num1" -gt "$num2" ] && echo "$num1 es mayor"
-
Verificar si dos números son iguales:
[ "$num1" -eq "$num2" ] && echo "Son iguales"
3. Verificar archivos y directorios
-
Verificar si un archivo existe:
[ -e archivo.txt ] && echo "El archivo existe"
-
Verificar si es un directorio:
[ -d /ruta/directorio ] && echo "Es un directorio"
-
Verificar si un archivo tiene permisos de lectura:
[ -r archivo.txt ] && echo "Tiene permisos de lectura"
Ejemplo práctico
Supongamos que queremos verificar si un archivo llamado config.txt
existe y tiene permisos de escritura antes de editarlo:
#!/bin/bash
archivo="config.txt"
if [ -e "$archivo" ]; then
if [ -w "$archivo" ]; then
echo "El archivo $archivo existe y tiene permisos de escritura."
else
echo "El archivo $archivo existe pero no tiene permisos de escritura."
fi
else
echo "El archivo $archivo no existe."
fi
Diferencia entre test
y []
Ambos funcionan de manera similar, pero []
es más común por ser más fácil de leer. Sin embargo, si usas test
, no tienes que preocuparte por los espacios extras que []
requiere.
¿Qué hay de [[ ]]
?
[[ ]]
es una versión mejorada y más flexible de []
disponible en Bash. Admite:
- Comparaciones regulares (como
=~
para expresiones regulares). - Evita errores en comparaciones de cadenas vacías.
Ejemplo con expresiones regulares:
cadena="hello123"
[[ $cadena =~ ^hello[0-9]+$ ]] && echo "Coincide con el patrón"
Conclusión
- Usa
test
o[]
para condiciones simples. - Usa
[[ ]]
para scripts más complejos en Bash. - Siempre ten cuidado con los espacios en
[]
, ya que olvidarlos puede generar errores.
Estas herramientas son esenciales en Shell Script para tomar decisiones dinámicas según las condiciones del sistema o del usuario.
Cuando usas un if
con una función dentro de []
, el comportamiento depende de cómo se evalúa el código de salida de la función y cómo []
maneja este resultado.
Funcionamiento general de if
En Bash, if
evalúa el código de salida de un comando o función. Por convención:
- Un código de salida
0
indica éxito (true). - Un código de salida distinto de
0
indica error (false).
Ejemplo básico:
my_function() {
return 3
}
if my_function; then
echo "True"
else
echo "False"
fi
Salida:
False
Esto ocurre porque my_function
devuelve un código de salida 3
(no 0
), lo que if
interpreta como falso.
Uso de []
en un if
Cuando encapsulas una función o comando dentro de []
:
[
no evalúa el código de salida directamente. En su lugar, evalúa el contenido como una expresión.- Si la expresión dentro de
[]
no está vacía, se considera true. - El código de salida de la función no afecta directamente la evaluación.
Ejemplo:
my_function() {
return 3
}
if [ my_function ]; then
echo "True"
else
echo "False"
fi
Salida:
True
Esto sucede porque [ my_function ]
no ejecuta la función. En su lugar, evalúa si el texto "my_function"
no está vacío (y cualquier texto no vacío es considerado true
).
Caso en que []
ejecuta la función
Si incluyes una ejecución explícita de la función dentro de []
, el resultado sigue sin depender del código de salida de la función, sino de cómo se interpreta la expresión.
Ejemplo:
my_function() {
return 3
}
if [ $(my_function) ]; then
echo "True"
else
echo "False"
fi
Salida:
False
Aquí, $(my_function)
ejecuta la función, pero como no produce una salida, el comando dentro de []
evalúa vacío (false
).
Diferencias clave entre []
y evaluar directamente la función
Caso | Resultado del if | Motivo |
---|---|---|
if my_function | Basado en return | Evalúa directamente el código de salida de la función (0 = true, distinto de 0 = false). |
if [ my_function ] | Siempre true | [ evalúa si "my_function" (una cadena no vacía) es true . |
if [ $(my_function) ] | Basado en salida | Evalúa el resultado de ejecutar la función. Si no genera salida, es false . |
Conclusión
- Sin
[]
: elif
usa directamente el código de salida de la función. - Con
[]
: no considera el código de salida de la función; evalúa si el contenido dentro de los corchetes estrue
ofalse
como una expresión. [ $(my_function) ]
sirve para compara salidas enecho
con texto si hacemos un return siembre sera falso
#!/bin/bash
# Nombre del archivo a buscar
archivo="mi_archivo.txt"
# Ruta donde buscar el archivo (puedes cambiar "." por otra ruta)
ruta="."
# Comando find: verifica si existe un archivo con nombre $archivo modificado en los últimos 30 minutos
if find "$ruta" -name "$archivo" -type f -mmin -30 | grep -q "$archivo"; then
echo "El archivo '$archivo' ya existe y fue modificado en los últimos 30 minutos."
else
echo "El archivo '$archivo' no existe o no fue modificado recientemente. Creándolo..."
touch "$ruta/$archivo"
fi
Expresiones para comando test
Categoría | Expresión | Verdadero si… |
---|---|---|
Números | integer1 -eq integer2 | integer1 es igual a integer2 . |
integer1 -ne integer2 | integer1 no es igual a integer2 . | |
integer1 -le integer2 | integer1 es menor o igual a integer2 . | |
integer1 -lt integer2 | integer1 es menor que integer2 . | |
integer1 -ge integer2 | integer1 es mayor o igual a integer2 . | |
integer1 -gt integer2 | integer1 es mayor que integer2 . | |
Cadenas de texto | string | La cadena no está vacía (string no es null ). |
-n string | La longitud de string es mayor a cero. | |
-z string | La longitud de string es igual a cero. | |
string1 = string2 | string1 y string2 son iguales. | |
string1 == string2 | string1 y string2 son iguales. | |
string1 != string2 | string1 y string2 no son iguales. | |
Archivos | file1 -ef file2 | file1 y file2 tienen el mismo número de inodo (hard link). |
file1 -nt file2 | file1 es más reciente que file2 . | |
file1 -ot file2 | file1 es más antiguo que file2 . | |
-b file | El archivo file existe y es un archivo especial de bloques (block-special). | |
-c file | El archivo file existe y es un archivo especial de caracteres. | |
-d file | El archivo file existe y es un directorio. | |
-e file | El archivo file existe. | |
-f file | El archivo file existe y es un archivo regular. | |
-k file | El archivo file existe y tiene el “sticky bit” activado. | |
-L file | El archivo file existe y es un enlace simbólico. | |
-s file | El archivo file existe y tiene longitud mayor a cero. | |
-u file | El archivo file existe y tiene el bit setuid activado. | |
-w file | El archivo file existe y es escribible (por el usuario efectivo). | |
-x file | El archivo file existe y es ejecutable (por el usuario efectivo). |
Ejemplo de uso
Evaluando números:
a=5
b=10
if [ $a -lt $b ]; then
echo "a es menor que b"
else
echo "a no es menor que b"
fi
Evaluando cadenas:
cadena="Hola"
if [ -n "$cadena" ]; then
echo "La cadena no está vacía"
else
echo "La cadena está vacía"
fi
Evaluando archivos:
if [ -f "/path/to/file.txt" ]; then
echo "El archivo existe"
else
echo "El archivo no existe"
fi
Sentencia if: Condiciones avanzadas
Esto hace perder a bash retrocompatibilidad ya que solo funciona en bash moderno
Expresiones avanzadas con if
usando [[ ]]
, wildcards y expresiones regulares en Bash
En Bash, las construcciones [[ ]]
se utilizan para realizar evaluaciones condicionales más avanzadas que las que se pueden hacer con los tradicionales test
o [ ]
. Cuando usamos [[ ]]
, obtenemos una sintaxis más poderosa que permite trabajar con wildcards, expresiones regulares y otras características. En este artículo, exploraremos cómo usar [[ ]]
con wildcards y expresiones regulares, y cómo aprovecharlos en condiciones if
para crear scripts más eficientes.
¿Qué son los wildcards en Bash?
Los wildcards (comodines) son caracteres que representan uno o más caracteres en cadenas de texto. Los más comunes son:
*
: Coincide con cualquier número de caracteres (incluido ninguno).?
: Coincide con un solo carácter.[]
: Coincide con cualquier carácter dentro de los corchetes.
Ejemplo de wildcards:
# Coincide con cualquier archivo que empiece con "archivo" y termine con ".txt"
ls archivo*.txt
Sintaxis avanzada con [[ ]]
El uso de [[ ]]
permite evaluaciones condicionales con una sintaxis más flexible que el comando test
. Dentro de [[ ]]
, se pueden usar comodines (*
, ?
, []
), además de otras funcionalidades que no están disponibles con test
.
1. Uso de wildcards con [[ ]]
En un bloque if
, puedes usar wildcards directamente dentro de las condiciones para evaluar patrones de coincidencia. Esto es útil para verificar si un archivo o una cadena de texto coincide con un patrón determinado.
Ejemplo 1: Coincidencia con *
(cualquier número de caracteres)
#!/bin/bash
filename="documento.txt"
if [[ $filename == documento*.txt ]]; then
echo "El archivo es un documento de texto"
else
echo "El archivo no es un documento de texto"
fi
En este caso, el patrón documento*.txt
coincide con cualquier archivo que empiece con “documento” y termine con “.txt”. Si filename
coincide con este patrón, la condición será verdadera.
Ejemplo 2: Coincidencia con ?
(un solo carácter)
#!/bin/bash
word="archivo1"
if [[ $word == archivo? ]]; then
echo "La palabra tiene 7 caracteres y termina en un dígito"
else
echo "La palabra no cumple con el patrón"
fi
Aquí, el ?
indica que cualquier único carácter puede seguir a “archivo”, lo que significa que el patrón coincidirá con cadenas como “archivo1”, “archivoA”, etc.
Ejemplo 3: Coincidencia con []
(un conjunto de caracteres)
#!/bin/bash
filename="documento1"
if [[ $filename == documento[0-9] ]]; then
echo "El archivo tiene un número al final"
else
echo "El archivo no tiene un número al final"
fi
El patrón documento[0-9]
coincide con cualquier cadena que empiece con “documento” y tenga un solo dígito del 0 al 9 al final.
2. Uso de expresiones regulares con [[ ]]
Otra característica poderosa de [[ ]]
es que soporta expresiones regulares, lo que permite realizar coincidencias más complejas que con los simples wildcards. Dentro de [[ ]]
, podemos usar la opción =~
para evaluar expresiones regulares.
Ejemplo 4: Coincidencia con una expresión regular
#!/bin/bash
string="El número es 1234"
if [[ $string =~ [0-9]{4} ]]; then
echo "La cadena contiene un número de 4 dígitos"
else
echo "La cadena no contiene un número de 4 dígitos"
fi
En este ejemplo, la expresión regular [0-9]{4}
busca un número de exactamente 4 dígitos dentro de la cadena. Si la cadena contiene este patrón, la condición es verdadera.
Ejemplo 5: Uso de expresiones regulares con caracteres especiales
#!/bin/bash
email="usuario@example.com"
if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$ ]]; then
echo "El correo electrónico es válido"
else
echo "El correo electrónico no es válido"
fi
En este caso, estamos utilizando una expresión regular para validar un correo electrónico. La expresión ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$
verifica si el formato del correo electrónico es correcto, es decir, si tiene el formato usuario@dominio.com
.
3. Combinando condiciones con [[ ]]
También puedes combinar múltiples condiciones dentro de un [[ ]]
, usando operadores lógicos como &&
(AND) o ||
(OR).
Ejemplo 6: Uso de &&
(AND)
#!/bin/bash
string="Hola123"
if [[ $string =~ [A-Za-z]+ && $string =~ [0-9]+ ]]; then
echo "La cadena contiene letras y números"
else
echo "La cadena no contiene letras y números"
fi
En este ejemplo, la condición es verdadera si la cadena contiene tanto letras como números.
Ejemplo 7: Uso de ||
(OR)
#!/bin/bash
filename="documento.txt"
if [[ $filename == *.txt || $filename == *.pdf ]]; then
echo "El archivo es de tipo texto o PDF"
else
echo "El archivo no es de tipo texto o PDF"
fi
Aquí, el archivo es considerado de tipo texto o PDF si su extensión es .txt
o .pdf
.
Resumen
[[ ]]
: Permite evaluaciones condicionales más poderosas que[ ]
ytest
, con soporte para wildcards y expresiones regulares.- Wildcards: Se usan dentro de
[[ ]]
para hacer coincidir patrones como*
,?
y[]
. - Expresiones regulares: Usando
=~
, puedes realizar coincidencias con patrones complejos. - Operadores lógicos: Se pueden combinar varias condiciones con
&&
(AND) o||
(OR) dentro de[[ ]]
.
Uso de (( ))
en Bash
El operador (( ))
en Bash es utilizado para realizar operaciones aritméticas, pero también puede ser utilizado para realizar comparaciones y trabajar con variables numéricas de manera eficiente. Se trata de una estructura de evaluación aritmética avanzada que permite realizar cálculos, comparaciones y asignaciones sin necesidad de utilizar el comando expr
o herramientas externas.
¿Qué hace (( ))
?
Dentro de (( ))
, puedes realizar operaciones aritméticas como suma, resta, multiplicación, división, y más. Además, permite realizar comparaciones numéricas y asignaciones de una manera mucho más fácil y rápida que con otras alternativas en Bash.
Características clave de (( ))
:
- Operaciones aritméticas: Permite realizar operaciones como suma, resta, multiplicación, división y módulo.
- Comparaciones: Facilita la comparación de valores numéricos utilizando operadores como
-eq
,-ne
,-gt
,-lt
, etc., pero con una sintaxis más simple. - Asignaciones: Puedes asignar resultados de operaciones aritméticas directamente a variables dentro de
(( ))
.
Sintaxis básica
(( expression ))
La expresión dentro de (( ))
es evaluada como una operación aritmética. Si la expresión es verdadera (no es igual a cero), el resultado de la evaluación será “exit status 0” (verdadero). Si la expresión es falsa (igual a cero), el resultado será “exit status 1” (falso).
Operaciones aritméticas comunes
1. Suma (+
)
#!/bin/bash
a=5
b=3
(( sum = a + b ))
echo $sum # Imprime 8
2. Resta (-
)
#!/bin/bash
a=10
b=4
(( diff = a - b ))
echo $diff # Imprime 6
3. Multiplicación (*
)
#!/bin/bash
a=6
b=7
(( product = a * b ))
echo $product # Imprime 42
4. División (/
)
#!/bin/bash
a=10
b=2
(( quotient = a / b ))
echo $quotient # Imprime 5
5. Módulo (resto de la división) (%
)
#!/bin/bash
a=10
b=3
(( remainder = a % b ))
echo $remainder # Imprime 1
Comparaciones numéricas dentro de (( ))
Dentro de (( ))
, se pueden realizar comparaciones utilizando los operadores estándar de Bash:
-eq
: Igual a (equal)-ne
: No igual a (not equal)-gt
: Mayor que (greater than)-lt
: Menor que (less than)-ge
: Mayor o igual que (greater than or equal to)-le
: Menor o igual que (less than or equal to)
Sin embargo, dentro de (( ))
, no es necesario usar el prefijo -
para las comparaciones, ya que estos operadores están simplificados:
==
: Igual!=
: No igual>
: Mayor que<
: Menor que>=
: Mayor o igual que<=
: Menor o igual que
Ejemplos de comparaciones dentro de (( ))
1. Comparación de igualdad (==
)
#!/bin/bash
a=5
b=5
if (( a == b )); then
echo "a es igual a b"
else
echo "a no es igual a b"
fi
2. Comparación de desigualdad (!=
)
#!/bin/bash
a=5
b=3
if (( a != b )); then
echo "a no es igual a b"
else
echo "a es igual a b"
fi
3. Comparación mayor que (>
)
#!/bin/bash
a=10
b=5
if (( a > b )); then
echo "a es mayor que b"
else
echo "a no es mayor que b"
fi
4. Comparación menor que (<
)
#!/bin/bash
a=3
b=7
if (( a < b )); then
echo "a es menor que b"
else
echo "a no es menor que b"
fi
5. Comparación mayor o igual que (>=
)
#!/bin/bash
a=8
b=8
if (( a >= b )); then
echo "a es mayor o igual que b"
else
echo "a no es mayor o igual que b"
fi
6. Comparación menor o igual que (<=
)
#!/bin/bash
a=6
b=10
if (( a <= b )); then
echo "a es menor o igual que b"
else
echo "a no es menor o igual que b"
fi
Usando (( ))
con variables no numéricas
Aunque (( ))
está diseñado para trabajar con números, también puedes usarlo con expresiones que evalúan condiciones verdaderas o falsas en función de su valor. Si la variable contiene un valor no numérico, Bash interpretará su valor en términos de 0 (falso) o cualquier valor distinto de cero (verdadero).
Ejemplo 1: Uso con booleanos
#!/bin/bash
a=5
if (( a )); then
echo "a es un valor verdadero"
else
echo "a es un valor falso"
fi
Aquí, como a
es un número distinto de cero, la condición es verdadera.
Resumen
(( ))
se utiliza para realizar operaciones aritméticas y comparaciones numéricas.- Dentro de
(( ))
, los operadores aritméticos son más simples que en el caso de[ ]
otest
. - Puedes usar
(( ))
para hacer comparaciones numéricas sin el prefijo-
, como==
,!=
,>
,<
,>=
,<=
. - Es posible realizar asignaciones dentro de
(( ))
, lo que lo hace más cómodo que usarexpr
o comandos externos. - Es ideal para condiciones donde se necesita evaluar operaciones matemáticas y comparaciones numéricas.
El uso de (( ))
simplifica muchas operaciones en Bash y hace que los scripts sean más fáciles de leer y escribir cuando se trata de cálculos y comparaciones numéricas.
AND , OR y NOT con [] y [[]]
En Bash, tanto [
como [[
son utilizados para evaluar condiciones dentro de una estructura if
. Sin embargo, hay diferencias clave en cómo se manejan las expresiones lógicas como AND, OR y NOT cuando se utilizan [
(conocido como test) y [[
(conocido como double brackets). A continuación, te explico cómo funcionan estas expresiones lógicas en ambos casos:
1. AND (&&
):
El operador AND devuelve verdadero si ambas condiciones son verdaderas. Se usa de manera diferente según utilices [
o [[
.
Con [
:
Para hacer un AND con [
(test), debes encadenar dos condiciones usando -a
(que significa “AND”). A continuación se muestra un ejemplo de cómo se utilizaría:
if [ $a -eq 5 -a $b -eq 10 ]; then
echo "Ambas condiciones son verdaderas"
fi
Nota: El operador -a
funciona solo con [
y no se recomienda su uso en expresiones complejas debido a limitaciones.
Con [[
:
Con [[
, el operador AND se expresa utilizando &&
. Esto es mucho más flexible y sencillo de usar, especialmente con cadenas o expresiones más complejas. Aquí tienes un ejemplo de cómo usarlo:
if [[ $a -eq 5 && $b -eq 10 ]]; then
echo "Ambas condiciones son verdaderas"
fi
2. OR (||
):
El operador OR devuelve verdadero si al menos una de las condiciones es verdadera. Similar al AND, se usa de manera diferente con [
y [[
.
Con [
:
Para hacer un OR con [
(test), debes usar el operador -o
(que significa “OR”). Aquí tienes un ejemplo:
if [ $a -eq 5 -o $b -eq 10 ]; then
echo "Al menos una de las condiciones es verdadera"
fi
Nota: Al igual que con -a
, el uso de -o
no siempre es ideal para expresiones más complejas.
Con [[
:
Con [[
, el operador OR se expresa utilizando ||
, que es más intuitivo y versátil. Un ejemplo sería:
if [[ $a -eq 5 || $b -eq 10 ]]; then
echo "Al menos una de las condiciones es verdadera"
fi
3. NOT (!
):
El operador NOT invierte el valor lógico de una condición. Si la condición es verdadera, se vuelve falsa, y si es falsa, se vuelve verdadera.
Con [
:
Para usar NOT con [
(test), puedes usar el operador !
al principio de la condición. Aquí tienes un ejemplo:
if [ ! $a -eq 5 ]; then
echo "La condición no es verdadera"
fi
Con [[
:
Con [[
, se usa también !
de forma similar para negar una condición. El uso con [[
puede ser más legible y manejar cadenas con mayor facilidad. Aquí tienes un ejemplo:
if [[ ! $a -eq 5 ]]; then
echo "La condición no es verdadera"
fi
Resumen: Comparación entre [
y [[
Operador | Con [ | Con [[ |
---|---|---|
AND | -a | && |
OR | -o | ` |
NOT | ! | ! |
Ventajas de [[
sobre [
:
- Mayor flexibilidad:
[[
permite expresiones regulares, no requiere que las variables estén entre comillas, y maneja cadenas con espacios o caracteres especiales más fácilmente. - Mejor manejo de errores:
[[
no tiene problemas con el espacio y las comillas en variables, mientras que[
requiere un manejo más cuidadoso.
En general, se recomienda usar [[
cuando sea posible debido a su mayor facilidad de uso y flexibilidad.
Comando exit
En Bash, los comandos return
y exit
se utilizan para salir de diferentes contextos, y entender sus diferencias es clave para escribir scripts efectivos. Aquí te explico sus funciones y diferencias con ejemplos prácticos.
1. return
Uso:
- Se utiliza dentro de funciones en Bash para salir de la función y devolver un valor de estado.
- El valor devuelto por
return
puede ser utilizado por el código que llama a la función para tomar decisiones. - Solo puede devolver un valor numérico (entre 0 y 255).
Ejemplo:
#!/bin/bash
my_function() {
echo "Dentro de la función"
return 42
}
my_function
echo "Código de salida de la función: $?" # $? contiene el código de salida del último comando.
Salida:
Dentro de la función
Código de salida de la función: 42
En este ejemplo, return
termina la ejecución de la función y proporciona un código de salida que puede ser capturado con $?
.
2. exit
Uso:
- Se utiliza para terminar completamente el script en cualquier punto.
- También puede devolver un valor numérico que indica el estado de salida del script al sistema operativo.
- A diferencia de
return
,exit
no está limitado al contexto de funciones; finaliza todo el proceso del script.
Ejemplo:
#!/bin/bash
echo "Inicio del script"
exit 1 # Termina el script inmediatamente con código de salida 1.
echo "Esto nunca se ejecutará"
Salida:
Inicio del script
El código posterior a exit
no se ejecutará porque finaliza todo el script.
Diferencias Clave
Aspecto | return | exit |
---|---|---|
Contexto de uso | Solo dentro de funciones. | En cualquier parte del script. |
Efecto | Sale de la función. | Termina completamente el script. |
Propósito | Indicar el resultado de la función. | Indicar el estado final del script. |
Código de salida | Devuelve un valor numérico al llamador de la función. | Devuelve un valor numérico al sistema operativo. |
Ejecución posterior | Continúa ejecutando el script. | No ejecuta el código posterior. |
3. Ejemplo Comparativo
A continuación, se muestra un ejemplo donde se usan ambos comandos para entender mejor cómo funcionan en un script:
#!/bin/bash
my_function() {
echo "Dentro de la función"
if [[ $1 -gt 10 ]]; then
echo "Valor demasiado alto, saliendo de la función"
return 1 # Sale de la función con código de error 1
fi
echo "Valor aceptable"
}
echo "Inicio del script"
my_function 15
if [[ $? -ne 0 ]]; then
echo "Error detectado en la función, terminando el script"
exit 1 # Termina el script con código de error 1
fi
echo "Fin del script"
Salida cuando se pasa 15
:
Inicio del script
Dentro de la función
Valor demasiado alto, saliendo de la función
Error detectado en la función, terminando el script
En este caso:
return
finaliza solo la función si se pasa un valor mayor a 10.exit
se usa para finalizar el script por completo si la función devuelve un error.
Resumen de Uso
- Usa
return
cuando solo necesitas salir de una función y devolver un código de salida para control de flujo. - Usa
exit
cuando necesitas terminar completamente el script, generalmente indicando éxito (exit 0
) o error (exit 1
o superior).
Ambos comandos son esenciales para controlar el flujo de un script, pero es importante elegir el adecuado según el contexto.
Bucle for
El bucle for
en Shell Script es una herramienta fundamental para iterar sobre listas de elementos, como palabras, números, resultados de comandos, archivos o directorios. Su simplicidad y flexibilidad lo hacen ideal para realizar tareas repetitivas.
A continuación, te explico en detalle cómo funciona el bucle for
en Shell Script.
1. Sintaxis básica
for variable in lista
do
# comandos
done
variable
: Toma cada valor delista
en cada iteración.lista
: Puede ser una lista explícita de valores, un rango, una salida de comando, o archivos.- Los comandos dentro del bloque
do...done
se ejecutan una vez por cada valor enlista
.
2. Ejemplo básico
#!/bin/bash
for color in rojo verde azul
do
echo "El color es $color"
done
Salida:
El color es rojo
El color es verde
El color es azul
Aquí, color
toma los valores rojo
, verde
y azul
en cada iteración.
3. Iteración sobre un rango de números
El bucle for
puede iterar sobre un rango numérico utilizando {inicio..fin}
:
#!/bin/bash
for num in {1..5}
do
echo "Número: $num"
done
Salida:
Número: 1
Número: 2
Número: 3
Número: 4
Número: 5
3.1 Con pasos específicos
Podemos definir un incremento o decremento con {inicio..fin..paso}
:
#!/bin/bash
for num in {10..1..2}
do
echo "Número: $num"
done
Salida:
Número: 10
Número: 8
Número: 6
Número: 4
Número: 2
4. Iteración sobre archivos en un directorio
El bucle for
es muy útil para procesar archivos o directorios:
#!/bin/bash
for file in *.txt
do
echo "Procesando archivo: $file"
done
Salida (si hay archivos .txt
en el directorio):
Procesando archivo: archivo1.txt
Procesando archivo: archivo2.txt
En este ejemplo, *.txt
expande a todos los archivos con esa extensión en el directorio actual.
5. Iteración sobre la salida de un comando
Puedes usar el resultado de un comando como la lista de elementos:
#!/bin/bash
for user in $(cat usuarios.txt)
do
echo "Usuario: $user"
done
Salida (si usuarios.txt
contiene nombres de usuarios):
Usuario: Juan
Usuario: Maria
Usuario: Pedro
Nota sobre espacios:
Si los elementos tienen espacios, es mejor usar un while con un read, ya que $(...)
divide por espacios. Para manejar esto correctamente, usa:
#!/bin/bash
while IFS= read -r user; do
echo "Usuario: $user"
done < usuarios.txt
6. Anidar bucles for
Puedes usar bucles for
dentro de otros para iterar sobre estructuras más complejas:
#!/bin/bash
for i in 1 2 3
do
for j in A B C
do
echo "Par: $i$j"
done
done
Salida:
Par: 1A
Par: 1B
Par: 1C
Par: 2A
Par: 2B
Par: 2C
Par: 3A
Par: 3B
Par: 3C
7. Ejemplo avanzado: Usando for
con condiciones
Supongamos que queremos encontrar archivos creados recientemente en un directorio y realizar acciones sobre ellos:
#!/bin/bash
for file in $(find . -type f -mtime -7)
do
echo "Archivo modificado en la última semana: $file"
done
En este ejemplo, el comando find
genera una lista de archivos, y el bucle for
los recorre.
8. Alternativa moderna: for ((exp1; exp2; exp3))
Esta variante del bucle for
es similar a los bucles de C. Se utiliza para iterar sobre expresiones aritméticas.
Ejemplo:
#!/bin/bash
for ((i=1; i<=5; i++))
do
echo "Iteración $i"
done
Salida:
Iteración 1
Iteración 2
Iteración 3
Iteración 4
Iteración 5
i=1
: Inicialización.i<=5
: Condición para continuar el bucle.i++
: Incremento en cada iteración.
9. Comparación for
vs while
El bucle for
es ideal cuando conoces de antemano la lista de elementos o el rango de iteración. Si necesitas ejecutar un bucle hasta que se cumpla una condición dinámica, es mejor usar un while
.
Resumen
El bucle for
en Bash es extremadamente versátil y se puede usar para:
- Recorrer listas de palabras, números o archivos.
- Procesar salidas de comandos.
- Trabajar con rangos numéricos.
- Anidar bucles para estructuras más complejas.
Bucle while
Un bucle while
en Shell Script es una forma de ejecutar un bloque de código repetidamente mientras se cumpla una condición. Es ideal para tareas que necesitan repetirse hasta que algo cambie.
El bucle while
en Shell Script
En Bash, el bucle while
ejecuta comandos repetidamente mientras una condición sea verdadera. Su estructura básica es:
while [ condición ]; do
# Código a ejecutar
done
[ condición ]
: Evalúa si la condición es verdadera. Si lo es, ejecuta el bloque de código dentro deldo
…done
.do
ydone
: Delimitan el cuerpo del bucle.
Ejemplo básico: Contador
Este script imprime números del 1 al 5:
#!/bin/bash
contador=1
while [ $contador -le 5 ]; do
echo "Número: $contador"
contador=$((contador + 1)) # Incrementa el contador
done
Explicación:
contador=1
: Inicializamos la variablecontador
con 1.[ $contador -le 5 ]
: Comprueba sicontador
es menor o igual a 5.echo
: Imprime el valor actual decontador
.contador=$((contador + 1))
: Incrementa la variable en 1.
Ejemplo avanzado: Leer un archivo línea por línea
Este script lee un archivo llamado nombres.txt
y muestra cada línea en pantalla:
#!/bin/bash
archivo="nombres.txt"
while IFS= read -r linea; do
echo "Nombre: $linea"
done < "$archivo"
Explicación:
IFS= read -r linea
: Lee cada línea del archivo y la asigna a la variablelinea
.done < "$archivo"
: Redirige el contenido denombres.txt
al bucle.
Ejemplo con un comando externo
Usa un bucle while
para realizar una tarea en intervalos regulares, como comprobar si un servicio está activo:
#!/bin/bash
servicio="apache2"
while systemctl is-active --quiet $servicio; do
echo "El servicio $servicio está activo"
sleep 5 # Espera 5 segundos antes de comprobar nuevamente
done
echo "El servicio $servicio se detuvo."
Explicación:
systemctl is-active --quiet $servicio
: Verifica si el servicio está activo.sleep 5
: Pausa el script durante 5 segundos antes de repetir el bucle.
Cuándo usar while
- Repetir tareas hasta que se cumpla una condición.
- Leer datos dinámicamente, como archivos o entradas del usuario.
- Monitorizar eventos o servicios.
Break and continue
Vamos a explicar los comandos break
y continue
en Bash.
¿Qué hace break
?
El comando break
termina un bucle inmediatamente, sin importar si la condición del bucle todavía es verdadera. En tu ejemplo, se usa para salir del bucle while
cuando el usuario selecciona la opción 4.
¿Qué hace continue
?
El comando continue
detiene la ejecución del ciclo actual y pasa directamente a la siguiente iteración del bucle. Esto significa que salta el resto del código en el ciclo actual, pero no rompe el bucle por completo.
Tu ejemplo adaptado con explicaciones
Aquí tienes un ejemplo funcional en un archivo .sh
, incorporando break
y continue
:
#!/bin/bash
while true; do
clear
cat <<EOF
Por favor seleccione una opción:
1. opción a
2. opción b
3. opción c
4. salir
EOF
read -p "Introduce la opción [1-4]: " REPLY
if [ "$REPLY" -eq 4 ]; then
echo "Saliendo del programa..."
break # Termina el bucle si elige 4
fi
if ! [[ "$REPLY" =~ ^[1-3]$ ]]; then
echo "Opción no válida, intenta nuevamente."
sleep 2
continue # Vuelve al inicio del bucle si la opción no es válida
fi
case $REPLY in
1)
echo "Has seleccionado la opción a."
;;
2)
echo "Has seleccionado la opción b."
;;
3)
echo "Has seleccionado la opción c."
;;
esac
echo "Presiona enter para continuar..."
read # Pausa para que el usuario vea el resultado
done
Al final de la linea
read -p "Introduce la opción [1-4]: " REPLY
VemosREPLY
esta es la variable por defecto podriamos omitirla, Pero por claridad la dejamos. Si quisieramos usar otro nombre de varibale ahi si tenemos que ponerla. read -p “Introduce la opción [1-4]: ” opciones
Cómo funciona este ejemplo:
-
while true
:- El bucle se ejecuta indefinidamente hasta que se use
break
.
- El bucle se ejecuta indefinidamente hasta que se use
-
break
:- Si el usuario introduce
4
, el bucle termina.
- Si el usuario introduce
-
continue
:- Si el usuario introduce algo que no está entre
1
y3
, muestra un mensaje de error y salta directamente a la siguiente iteración del bucle.
- Si el usuario introduce algo que no está entre
-
case
:- Se utiliza para manejar las opciones seleccionadas por el usuario (
1
,2
,3
).
- Se utiliza para manejar las opciones seleccionadas por el usuario (
Guardar este script como archivo .sh
-
Copia el código y guárdalo en un archivo llamado
menu.sh
:nano menu.sh
-
Haz que el archivo sea ejecutable:
chmod +x menu.sh
-
Ejecuta el script:
./menu.sh
Con este ejemplo, el usuario puede navegar por el menú, y el script manejará correctamente las opciones, salidas y entradas no válidas.
La Sentencia until
en Shell Script
La sentencia until
en Bash es una estructura de control de bucles que ejecuta un bloque de código hasta que se cumpla una condición específica. Es la contraparte del bucle while
, pero con la lógica invertida.
Sintaxis básica
until [ condición ]; do
# Bloque de código a ejecutar
done
condición
: Es una expresión que se evalúa antes de cada iteración. El bucle continúa ejecutándose mientras la condición sea falsa.do
ydone
: Delimitan el bloque de código que se ejecutará repetidamente.
¿Cómo funciona until
?
El bucle until
repite el bloque de código mientras la condición sea falsa. Una vez que la condición se evalúa como verdadera, el bucle termina.
Ejemplo básico
#!/bin/bash
contador=1
until [ $contador -gt 5 ]; do
echo "Número: $contador"
contador=$((contador + 1)) # Incrementa el contador
done
Explicación del ejemplo:
- Inicialización:
contador=1
. - Condición:
[ $contador -gt 5 ]
(El bucle se ejecuta mientras$contador
sea menor o igual a 5). - Incremento: Se incrementa el valor de
contador
en cada iteración.
Salida esperada:
Número: 1
Número: 2
Número: 3
Número: 4
Número: 5
Ejemplo con entrada del usuario
Vamos a usar un bucle until
para forzar al usuario a introducir una contraseña correcta:
#!/bin/bash
contraseña="secreta"
entrada=""
until [ "$entrada" = "$contraseña" ]; do
read -sp "Introduce la contraseña: " entrada
echo
if [ "$entrada" != "$contraseña" ]; then
echo "Contraseña incorrecta, intenta de nuevo."
fi
done
echo "¡Contraseña correcta!"
Explicación del ejemplo:
- Condición: El bucle se ejecuta hasta que la entrada del usuario sea igual a
"secreta"
. read -sp
: Solicita al usuario introducir una contraseña sin mostrarla en la terminal.- Mensaje: Si la contraseña es incorrecta, muestra un mensaje de error.
Diferencia entre while
y until
while | until |
---|---|
Ejecuta el bloque mientras la condición es verdadera. | Ejecuta el bloque mientras la condición es falsa. |
Se detiene cuando la condición es falsa. | Se detiene cuando la condición es verdadera. |
Ejemplo: while [ $contador -le 5 ]; do | Ejemplo: until [ $contador -gt 5 ]; do |
Ejemplo combinado: until
con un contador decreciente
#!/bin/bash
contador=10
until [ $contador -lt 1 ]; do
echo "Cuenta regresiva: $contador"
contador=$((contador - 1))
done
echo "¡Despegue!"
Salida esperada:
Cuenta regresiva: 10
Cuenta regresiva: 9
Cuenta regresiva: 8
...
Cuenta regresiva: 1
¡Despegue!
¿Cuándo usar until
?
- Cuando necesitas ejecutar un bloque de código hasta que una condición sea verdadera.
- Es útil en situaciones donde quieres forzar un comportamiento repetido hasta que el programa llegue a un estado deseado (como en validaciones o esperas condicionales).
Case
El Uso de case
en Shell Script
La sentencia case
en Bash se utiliza para comparar una variable o expresión contra múltiples patrones. Es similar al switch
en otros lenguajes, pero más potente gracias al soporte para expresiones regulares y shell expansion.
Sintaxis básica
case variable in
patrón1)
# Bloque de código si coincide patrón1
;;
patrón2)
# Bloque de código si coincide patrón2
;;
*)
# Bloque de código si no coincide ningún patrón (opcional)
;;
esac
variable
: Es la entrada que se evalúa (por ejemplo, texto ingresado por el usuario).patrón
: Son condiciones o expresiones que se comparan con el valor de la variable.;;
: Marca el final de cada bloque de código.*)
: Es el caso predeterminado (similar aldefault
).
Ejemplo básico
#!/bin/bash
echo "Introduce una opción (a, b o c):"
read opcion
case $opcion in
a)
echo "Elegiste la opción A."
;;
b)
echo "Elegiste la opción B."
;;
c)
echo "Elegiste la opción C."
;;
*)
echo "Opción no válida."
;;
esac
Cómo funciona:
- Si el usuario introduce
a
, se ejecuta el bloque asociado al patróna)
. - Si introduce algo diferente a
a
,b
oc
, el caso*)
se ejecuta como opción predeterminada.
Opciones avanzadas de case
1. Uso de comodines en los patrones
*
: Coincide con cualquier cadena de caracteres.?
: Coincide con un solo carácter.[ ]
: Define rangos o conjuntos de caracteres.
case $opcion in
[a-c]) # Coincide con a, b o c
echo "Seleccionaste una opción válida: $opcion"
;;
?)
echo "Un solo carácter, pero no válido."
;;
*)
echo "Opción inválida."
;;
esac
2. Uso de Shell Expansion
Shell expansion permite trabajar con múltiples opciones de forma compacta, por ejemplo:
case $opcion in
{start,stop,restart})
echo "Ejecutando acción: $opcion"
;;
*)
echo "Acción desconocida."
;;
esac
Nota: Aunque las llaves {}
funcionan en Bash para la expansión, es más común utilizar |
para opciones múltiples.
Expresiones regulares en case
Aunque case
no soporta expresiones regulares completas (como con grep
o [[ ]]
), sí permite usar patrones avanzados como:
-
Inicio y fin de cadenas:
abc*
: Coincide con cualquier cadena que comience con “abc”.*xyz
: Coincide con cualquier cadena que termine con “xyz”.
-
Rangos de caracteres:
[a-z]
: Coincide con cualquier carácter en el rangoa
az
.[0-9]
: Coincide con cualquier número.
-
Patrones múltiples (usando
|
):(patrón1|patrón2)
: Coincide con cualquiera de los patrones.
Ejemplo:
echo "Introduce un texto:"
read texto
case $texto in
[0-9]*) # Comienza con un número
echo "Comienza con un número."
;;
*[a-z]) # Termina con una letra minúscula
echo "Termina con una letra minúscula."
;;
*.txt) # Coincide con archivos .txt
echo "Es un archivo de texto."
;;
*)
echo "No coincide con ningún patrón."
;;
esac
Complemento con Shell Expansion
Shell expansion puede hacer más dinámico el uso de case
, por ejemplo:
Usando case
para comprobar archivos
archivo="prueba.txt"
case $archivo in
*.txt)
echo "Es un archivo de texto."
;;
*.sh)
echo "Es un script de shell."
;;
*)
echo "Tipo de archivo desconocido."
;;
esac
Listar comandos válidos
comando="start"
case $comando in
start|stop|restart)
echo "Ejecutando comando: $comando"
;;
*)
echo "Comando no reconocido."
;;
esac
Ejemplo práctico: Validación de entradas
#!/bin/bash
echo "Introduce tu opción (número del 1 al 5, o texto específico):"
read entrada
case $entrada in
[1-5])
echo "Ingresaste un número válido: $entrada"
;;
start|stop|restart)
echo "Comando reconocido: $entrada"
;;
*.log)
echo "Es un archivo de log: $entrada"
;;
"")
echo "No ingresaste nada."
;;
*)
echo "Entrada no válida."
;;
esac
Resumen
case
es ideal para evaluar múltiples condiciones sin anidar variosif-else
.- Soporta comodines, shell expansion y patrones avanzados.
- Simplifica la lógica del script, especialmente cuando se trata de manejar múltiples opciones.
Uso de ;; y ;;&
Diferencias entre 1 | 2)
y 2)
en case
Cuando usas case
en un script de Bash, hay dos maneras de manejar patrones que pueden coincidir con una misma entrada:
1 | 2)
: Permite que varias condiciones ejecuten el mismo bloque de código.2)
: Define un caso exclusivo para una sola condición.
Ejemplo: Uso de 1 | 2)
y 2)
Supongamos que tienes el siguiente script:
#!/bin/bash
read -p "Introduce un número: " num
case $num in
1 | 2)
echo "Seleccionaste 1 o 2."
;;
2)
echo "Seleccionaste exactamente 2."
;;
*)
echo "No coincide con ningún caso."
;;
esac
-
Si introduces
1
, el bloque1 | 2)
se ejecutará y mostrará:Seleccionaste 1 o 2.
-
Si introduces
2
, el primer bloque (1 | 2)
) coincide primero, por lo que no se evalúa el segundo caso. La salida será:Seleccionaste 1 o 2.
-
Si introduces cualquier otro número, el bloque predeterminado (
*
) se ejecutará:No coincide con ningún caso.
Nota: En case
, una vez que encuentra un patrón coincidente, el bloque correspondiente se ejecuta y no evalúa el resto de los casos, a menos que uses ;&
o ;;&
.
Uso de ;&
El modificador ;&
permite que, después de ejecutar un bloque de código, el flujo del programa continúe evaluando el siguiente caso sin importar la coincidencia.
Ejemplo con ;&
#!/bin/bash
read -p "Introduce un número: " num
case $num in
1)
echo "Es 1."
;;&
2)
echo "Es 2 (o después de 1 si usaste ;;&)."
;;
*)
echo "Es otra opción."
;;
esac
-
Si introduces
1
:- Coincide con el primer caso
1)
, imprime:Es 1.
- Luego, continúa evaluando el caso
2)
y, si es aplicable, ejecuta ese bloque también:Es 2 (o después de 1 si usaste ;;&).
Salida completa:
Es 1. Es 2 (o después de 1 si usaste ;;&).
- Coincide con el primer caso
-
Si introduces
2
, solo se ejecuta el bloque correspondiente:Es 2 (o después de 1 si usaste ;;&).
-
Si introduces cualquier otro número:
- El caso predeterminado (
*
) se ejecuta:Es otra opción.
- El caso predeterminado (
Uso de ;;&
El modificador ;;&
permite que, después de ejecutar un bloque, el flujo del programa continúe evaluando todos los casos restantes para buscar coincidencias adicionales.
Ejemplo con ;;&
#!/bin/bash
read -p "Introduce un número: " num
case $num in
1)
echo "Es 1."
;;&
2)
echo "Es 2."
;;&
*)
echo "Es otra opción."
;;
esac
-
Si introduces
1
, el flujo pasa por cada caso y evalúa si también coincide con otros patrones:- Coincide con el primer caso y ejecuta:
Es 1.
- Luego, verifica si coincide con
2)
y lo ejecuta:Es 2.
- Finalmente, ejecuta el caso
*
porque siempre aplica:Es otra opción.
Salida completa:
Es 1. Es 2. Es otra opción.
- Coincide con el primer caso y ejecuta:
-
Si introduces
2
, el flujo evaluará los siguientes casos:- Coincide con el caso
2)
y ejecuta:Es 2.
- Luego, evalúa el caso
*
y ejecuta:Es otra opción.
Salida completa:
Es 2. Es otra opción.
- Coincide con el caso
-
Si introduces cualquier otro número:
- Solo se ejecuta el caso predeterminado:
Es otra opción.
- Solo se ejecuta el caso predeterminado:
Diferencias entre ;;
, ;&
y ;;&
Modificador | Comportamiento |
---|---|
;; | Termina el caso actual y no evalúa los siguientes casos. |
;& | Continúa con el siguiente caso, ejecutando su bloque de código, sin comprobar coincidencias. |
;;& | Continúa evaluando todos los casos restantes, verificando coincidencias. |
Conclusión
1 | 2)
agrupa patrones para ejecutar el mismo bloque de código.2)
evalúa exclusivamente el caso donde la variable es igual a2
.;&
permite ejecutar el siguiente caso sin verificar coincidencias.;;&
fuerza la evaluación de todos los casos restantes, buscando coincidencias adicionales.
Ejemplo de proyecto final
#!/bin/bash
# Este programa parsea los resultados de nmap y construye un documento HTML
TITULO="Resultados nmap"
FECHA_ACTUAL="$(date)"
TIMESTAMP="Informe generado el $FECHA_ACTUAL por el usuario $USERNAME"
nmap_report() {
# Generamos el reporte raw con nmap
echo "[INFO] Ejecutando nmap en la red $1, por favor espere unos segundos..."
sudo nmap -sV "$1" > "$2"
echo "[OK] Fichero $2 generado correctamente"
# Dividimos el fichero por líneas vacías
echo "[INFO] Dividiendo el fichero $2..."
csplit "$2" '/^$/' {*} > /dev/null
echo "[OK] Fichero $2 dividido en los siguientes ficheros: $(ls xx*)"
return 0
}
result_parser() {
for i in xx*; do
host_ip=$(grep -E 'Nmap scan report ' $i | grep -E -o '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
if [ "$host_ip" ]; then
echo "<tr>"
echo "<td>$host_ip</td>"
# Obtenemos los puertos abiertos
puertos_abiertos=$(grep -E -h '^[0-9]{1,5}/(tcp|udp) open' $i | grep -E -o '^[0-9]{1,5}/(tcp|udp)')
if [ "$puertos_abiertos" ]; then
echo "<td>$puertos_abiertos</td>"
else
echo "<td>No hay puertos abiertos</td>"
fi
# Obtenemos los servicios
servicios=$(grep -E -h '^[0-9]{1,5}/(tcp|udp) open' $i | grep -E -o ' .* ')
if [ "$servicios" ]; then
echo "<td>$servicios</td>"
else
echo "<td>No hay servicios expuestos</td>"
fi
echo "</tr>"
fi
done
return 0
}
generar_html() {
cat <<EOF
<html>
<head>
<title>$TITULO</title>
</head>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
</style>
<body>
<h1>$TITULO</h1>
<p>$TIMESTAMP</p>
<table>
<tr>
<th>Host IP</th>
<th>Puertos abiertos</th>
<th>Servicio</th>
</tr>
$(result_parser)
</table>
</body>
</html>
EOF
}
if [ $(find salida_nmap.raw -mmin -30 2>/dev/null) ]; then
while true; do
read -p "Existe salida_nmap.raw con antigüedad menor a 30 minutos. ¿Sobreescribir? [y/n]: " REPLY
case "$REPLY" in
y)
# Generamos el reporte raw con nmap
nmap_report "192.168.239.0/24" "salida_nmap.raw"
break
;;
n)
echo "[INFO] Utilizando el fichero salida_nmap.raw existente"
break
;;
*)
echo "[ERROR] Respuesta no válida. Por favor, introduzca 'y' o 'n'."
;;
esac
done
else
# Generamos el reporte raw con nmap
nmap_report "192.168.239.0/24" "salida_nmap.raw"
fi
# Generamos el reporte con los resultados de nmap en HTML
echo "[INFO] Generando reporte HTML..."
generar_html > resultados_nmap.html
echo "[OK] Reporte resultados_nmap.html generado correctamente"