- Aprender
- Informática
- TI, redes y nube
- Introducción a Linux
- Guiones de Bash
Guiones de Bash: variables, códigos de salida y argumentos
PrincipianteUnidad 4 de 7 del curso Curso de Introducción a Linux
Lo que aprenderás
- Convierte una secuencia de comandos que escribes una y otra vez en un archivo de guion, comienza con la línea de intérprete adecuada y ejecútalo desde cualquier directorio.
- Convierte comandos repetidos en un archivo de guionEscribe comandos en orden en un archivo de texto sin formato, añade comentarios y comienza el archivo con una línea de intérprete que indique Bash como intérprete.
- Ejecuta un guion y elige dónde guardarloHaz que un guion sea ejecutable, ejecútalo mediante su ruta o un intérprete, colócalo en un directorio incluido en PATH y aprende cuándo puede modificar tu intérprete de comandos actual.
- Convierte comandos repetidos en un archivo de guion
- Guarda texto, números y salidas de comandos en variables, lee la entrada del usuario y usa comillas para que los espacios y caracteres especiales lleguen intactos a los comandos.
- Crea, lee y exporta variablesAsigna y usa variables del intérprete de comandos, elige buenos nombres, lee la entrada del usuario y pasa variables a los programas que inicia un guion.
- Protege palabras, variables y caracteres especiales mediante comillasElige entre comillas simples, comillas dobles y barras invertidas, y protege cada expansión de variable con comillas para que los espacios y comodines de los valores no alteren un comando.
- Captura la salida de comandos y realiza cálculos con números enterosAlmacena la salida de un comando mediante sustitución de comandos y realiza operaciones con números enteros, por ejemplo para crear nombres de archivo con fecha y mantener contadores.
- Crea, lee y exporta variables
- Lee y establece el estado de salida de comandos y guiones, encadena comandos según su éxito o fallo, y detecta y detiene errores antes de que causen daños.
- Lee y establece códigos de salida y encadena comandos según sus resultadosUsa el estado de salida que devuelve cada comando, termina un guion con un código significativo y ejecuta comandos solo cuando uno anterior haya tenido éxito o haya fallado.
- Detecta errores y detén un guion de forma seguraComprueba y traza un guion para detectar errores, envía mensajes de error a la salida de error estándar y haz que el guion se detenga ante fallos, variables no establecidas y cadenas de comandos que fallen.
- Lee y establece códigos de salida y encadena comandos según sus resultados
- Comprueba archivos, texto y números, elige qué hacer con if y case, y repite comandos sobre listas, archivos y líneas con bucles for, while y until.
- Realiza pruebas con archivos, cadenas y númerosEscribe condiciones con test, [ ] y [[ ]] que comprueben si existen archivos, comparen texto y comparen números enteros, y combínalas o niégalas.
- Elige acciones con if, elif, else y caseEjecuta distintos comandos según una condición con if, elif y else, y compara un valor con varios patrones mediante case.
- Repite comandos sobre listas y archivos con forRecorre una lista de palabras, los archivos que coinciden con un patrón, un rango de números o los argumentos de un guion, y maneja nombres de archivo con espacios.
- Repite tareas hasta que cambie una condición con while y untilEjecuta comandos mientras una condición tenga éxito o hasta que lo tenga, lee un archivo línea por línea y controla los bucles con break, continue y sleep.
- Realiza pruebas con archivos, cadenas y números
- Proporciona la entrada de un guion en la línea de comandos, lee los argumentos dentro del guion, compruébalos y proporciona valores predeterminados para que el mismo guion funcione en muchos casos.
- Lee los parámetros posicionales y el número de argumentosUsa
$0, de$1a$9,${10},$#y"$@"para leer las palabras que se indican después del nombre de un guion, y usashiftpara recorrerlas. - Comprueba argumentos, muestra instrucciones de uso y establece valores predeterminadosValida el número y el tipo de argumentos, muestra un mensaje de uso y termina con un código de error, usa valores predeterminados y gestiona opciones sencillas.
- Lee los parámetros posicionales y el número de argumentos
- Ejecuta guiones a horas o intervalos fijos sin tener una sesión abierta, con cron o temporizadores de systemd, y comprueba que las ejecuciones programadas se produzcan y terminen correctamente.
- Programa tareas con cronEscribe entradas de crontab con los cinco campos de tiempo, edítalas y enuméralas con crontab, y prepara los guiones para el entorno mínimo de cron.
- Programa tareas con temporizadores de systemdAsocia una unidad de servicio con una unidad de temporizador, escribe programaciones de calendario y de intervalos, habilita el temporizador y comprueba la próxima ejecución y los registros.
- Programa tareas con cron
Guía de estudio de Guiones de Bash
1Escribe y ejecuta tus primeros guiones de Bash
Es más fácil repetir unos cuantos comandos cuando están en un mismo guion. Asignarás al archivo un intérprete de Bash, mantendrás sus instrucciones legibles y elegirás cómo iniciarlo. Los permisos de archivos, las rutas de búsqueda de comandos y los intérpretes hijos explican varias sorpresas habituales: por qué un guion funciona con bash pero falla con ./, por qué no se encuentra su nombre y por qué sus cambios de directorio no desplazan tu terminal.
1.1 Convierte comandos repetidos en un archivo de guion
Un guion del intérprete de comandos guarda una secuencia de comandos en un archivo de texto sin formato. Bash lee los comandos en orden, igual que lee los que introduces en un indicador de comandos. Un guion puede repetir una tarea sin que alguien escriba cada paso y te proporciona un único lugar donde corregirla o mejorarla.
Pon el intérprete en la primera línea
La línea de intérprete indica a Linux qué programa debe leer un guion ejecutable. Comienza un guion de Bash con #!/bin/bash. Los caracteres #! deben ser los dos primeros del archivo: no debe haber espacios ni una línea en blanco antes de ellos. Bash es Bourne Again Shell. Se usa ampliamente como intérprete de comandos interactivo en Linux y también lee archivos de guion.
Un intérprete es un programa que lee y ejecuta otro lenguaje. El mismo mecanismo permite que #!/usr/bin/python3 seleccione Python o que #!/usr/bin/awk -f seleccione awk. El resto de un guion de Bash debe contener comandos que Bash entienda.
Crea backup-notes.sh en un editor de texto sin formato como nano o vi:
#!/bin/bash
# Keep a copy of the notes and show the backup folder.
mkdir -p ~/backup
cp ~/notes.txt ~/backup/
ls -l ~/backup
Bash primero crea el directorio de destino, después copia las notas y luego lista el destino. mkdir -p también tiene éxito cuando el directorio ya existe, por lo que una ejecución posterior puede reutilizarlo. El archivo de origen ~/notes.txt debe existir para que la copia funcione. Guardar los comandos no crea ese archivo de origen.
Haz que las personas puedan leer el archivo
La segunda línea es un comentario. Fuera del texto protegido por comillas, # inicia un comentario al principio de una palabra; Bash ignora el resto de esa línea. Escribe comentarios sobre el propósito de un paso, por ejemplo por qué debe conservarse una copia de seguridad. Las líneas en blanco y la sangría facilitan la identificación de grupos de comandos. Mantén una sangría coherente a medida que añadas condiciones y bucles.
La terminación .sh ayuda a reconocer un guion del intérprete de comandos. Linux no exige esa terminación y añadirla no selecciona Bash ni concede permiso de ejecución. Un archivo llamado backup-notes puede ejecutar los mismos comandos.
Ajusta el intérprete al lenguaje
| Primera línea | Cómo se elige el intérprete |
|---|---|
#!/bin/bash | Usa Bash en la ruta fija /bin/bash. |
#!/usr/bin/env bash | Usa env para buscar Bash mediante PATH. |
#!/bin/sh | Usa sh del sistema, que puede ser otro intérprete de comandos. |
En Debian y Ubuntu, /bin/sh normalmente selecciona dash. Las funciones de Bash como [[ ... ]] fallan ahí. Un guion de Bash necesita un intérprete de Bash aunque algunos comandos sencillos funcionen en ambos intérpretes. Llamar a un archivo something.sh no corrige una línea de intérprete inadecuada.
Reconoce un problema de finales de línea
Los editores de Windows pueden guardar un retorno de carro antes de cada salto de línea. En Linux, ese carácter invisible puede pasar a formar parte de la ruta de la línea de intérprete. Un error como /bin/bash^M: bad interpreter: No such file or directory señala este problema, aunque /bin/bash exista.
Convierte el archivo a finales de línea de Unix con dos2unix backup-notes.sh y guarda los futuros guiones con finales de línea de Unix en el editor. Los comandos del archivo pueden ser correctos y, aun así, el carácter adicional impedir que Linux inicie su intérprete.
Puntos clave
- Un guion es texto sin formato que contiene comandos para ejecutar en orden.
- La línea de intérprete debe comenzar al principio mismo del archivo e indicar el intérprete adecuado.
- Usa comentarios y sangría para aclarar el propósito y la estructura.
- La extensión
.shes una convención; no selecciona un intérprete de comandos. - Los finales de línea de Unix evitan que un retorno de carro oculto impida el funcionamiento de la línea de intérprete.
1.2 Ejecuta un guion y elige dónde guardarlo
Bash puede leer un guion directamente o iniciarlo como programa. Estas formas difieren en los permisos que necesitan y en cómo se elige el intérprete. La ruta que escribes también determina si el intérprete de comandos busca un comando o usa un archivo concreto.
Dos formas de iniciar el mismo archivo
bash backup-notes.sh
chmod u+x backup-notes.sh
./backup-notes.sh
El primer comando inicia Bash y le pide que lea el archivo. El guion necesita permiso de lectura; no requiere su propio bit de ejecución. Bash trata la línea de intérprete como un comentario porque el intérprete ya se ha elegido.
El segundo comando añade permiso de ejecución para el propietario del archivo. En una cadena de permisos como -rwxr--r--, la x del propietario indica que es ejecutable. El tercer comando ejecuta el archivo como programa y usa su línea de intérprete. chmod +x también es habitual; si no se indica una clase de permisos, umask limita qué clases reciben permiso de ejecución. chmod u+x selecciona explícitamente al propietario.
Si ./backup-notes.sh informa «Permission denied», comprueba el permiso de ejecución y el acceso a la ruta. Que bash backup-notes.sh funcione no demuestra que la ejecución directa tenga los permisos necesarios.
Comprende la búsqueda de comandos
./ significa el directorio actual. Cuando un comando contiene una barra, Bash sigue esa ruta. Cuando escribes un nombre sin barra, Bash busca en los directorios de PATH. El directorio actual normalmente no está en esa lista, por lo que estar dentro del directorio de un guion no basta para ejecutarlo solo por su nombre.
echo "$PATH"
command -v backup-notes.sh
type backup-notes.sh
PATH es una lista separada por dos puntos, como /home/sam/.local/bin:/usr/local/bin:/usr/bin:/bin. Se usa el primer ejecutable que coincide. Los dos últimos comandos ayudan a identificar qué se ejecutará para un nombre, incluida una copia más antigua en otro lugar de PATH.
Para que un guion personal esté disponible por su nombre, colócalo en un directorio de tu PATH. Muchas distribuciones añaden ~/bin o ~/.local/bin al iniciar sesión si ese directorio existe; comprueba tu PATH real. /usr/local/bin es una ubicación habitual para guiones compartidos por los usuarios y requiere permisos de administrador para escribir en él.
Elige entre un intérprete hijo y el intérprete actual
Ejecutar ./settings.sh o bash settings.sh inicia un proceso hijo de Bash. Sus variables y cambios de directorio pertenecen a ese proceso hijo. Un guion que contiene cd /var/log no desplaza el terminal que lo inició. Cuando termina, sigues en el directorio original del terminal.
La ejecución de un archivo en el intérprete actual (sourcing) lee comandos en el intérprete actual:
source ./settings.sh
# Equivalent short form:
. ./settings.sh
Úsala para un archivo de configuración destinado a cambiar tu sesión. Esta forma de ejecución necesita permiso de lectura, no de ejecución, y la línea de intérprete no inicia un intérprete separado. Por tanto, ejecutar así un archivo de configuración de Bash presupone que el intérprete actual entiende la sintaxis de Bash.
Lee el resultado de una ejecución
Inmediatamente después de que termine un guion, echo $? muestra su estado de salida. Salvo que el guion use exit con un código elegido, su estado procede del último comando. Por tanto, un listado final correcto puede ocultar una copia que falló antes; las comprobaciones de errores que verás más adelante permitirán que el guion indique el resultado real de la tarea.
Puntos clave
bash filelee un guion con Bash;./filenecesita permiso de ejecución y usa la línea de intérprete.- Solo se busca en PATH para nombres de comandos sin barra.
- Comprueba un nombre de comando con
command -votype. - La ejecución inicia un intérprete hijo; ejecutar un archivo en el intérprete actual puede modificarlo.
2Almacena valores en variables y protégelos con comillas de forma segura
Las variables permiten que los mismos comandos funcionen con rutas, nombres y recuentos cambiantes. La protección mediante comillas mantiene esos valores intactos mientras Bash construye una línea de comandos, de modo que un espacio en un nombre siga formando parte de él. Leerás entradas, pasarás valores a programas hijos, capturarás la salida de comandos y calcularás con números enteros. Estos elementos funcionan juntos cuando un guion crea un nombre de archivo con fecha o mantiene un recuento acumulado.
2.1 Crea, lee y exporta variables
Una variable da un nombre a un valor para que el mismo guion pueda reutilizarlo. Las variables de Bash normalmente contienen texto, incluso cuando ese texto parece un número. Asignas el valor una vez y expandes el nombre dondequiera que un comando necesite ese valor.
Asigna sin espacios
city=Lisbon
greeting="Good morning"
echo "$greeting from $city"
La salida es «Good morning from Lisbon». No hay espacios alrededor del = de asignación. En city = Lisbon, Bash trata city como un comando y las demás palabras como argumentos. Las comillas alrededor de "Good morning" mantienen ambas palabras en un solo valor.
Usa letras, dígitos y guiones bajos en los nombres de variables, con una letra o un guion bajo al principio. Los nombres distinguen entre mayúsculas y minúsculas: file, File y FILE son distintos. Elige nombres en minúsculas como backup_dir para los valores propios de tu guion. Esto ayuda a evitar que se sustituyan variables de entorno como PATH o HOME. Establecer PATH=/data cambia la resolución de comandos y puede hacer que dejen de encontrarse comandos habituales.
Indica dónde termina un nombre
Un signo de dólar introduce una expansión. Las llaves muestran el límite cuando sigue más texto inmediatamente:
file=report
echo "${file}_old"
Esto muestra «report_old». Con "$file_old", Bash busca una variable llamada file_old, no file seguido de _old. Sin set -u, un nombre no establecido se expande a texto vacío. Por tanto, un error de escritura puede producir una ruta o un mensaje vacío sin un error inmediato.
Un valor como count=5 almacena el texto «5». Añadir texto junto a una expansión no calcula: echo "$count+1" muestra «5+1». La expansión aritmética da a los números una función diferente cuando se necesitan cálculos.
Lee una línea de entrada
read -r -p "Your name: " name
echo "Hello, $name"
read almacena la línea introducida en name. -p proporciona la indicación y -r conserva las barras invertidas. Con la entrada «Lee Kim», el saludo es «Hello, Lee Kim». Un guion ejecutado sin una persona presente necesita obtener su entrada de argumentos, archivos o valores predeterminados; una indicación no puede proporcionar de forma fiable un valor que falta.
Exporta valores para programas hijos
Una variable ordinaria del intérprete de comandos pertenece al intérprete donde se establece. La exportación la marca para incluirla en el entorno que se copia a los programas que inicia ese intérprete:
export BACKUP_DIR=/mnt/usb
bash backup-notes.sh
El proceso hijo de Bash puede ahora leer BACKUP_DIR. Si ese proceso hijo asigna otro valor, el proceso padre conserva el suyo. La herencia del entorno va del padre al hijo; no envía los cambios posteriores de vuelta al padre.
| Nombre | Significado habitual |
|---|---|
HOME | Directorio personal |
USER | Nombre de usuario |
PWD | Directorio de trabajo actual |
PATH | Directorios donde se buscan nombres de comandos |
env o printenv muestra las variables de entorno. unset name elimina la variable llamada name; no asigna una cadena vacía. Con una expansión normal ambas pueden parecer vacías, pero una comprobación de variables no establecidas puede distinguir una variable ausente de una establecida.
Puntos clave
- Las asignaciones usan
name=valuesin espacios alrededor de=. - Los nombres de variables distinguen entre mayúsculas y minúsculas; usa nombres en minúsculas para tus propios valores.
${name}marca el final del nombre de una variable antes del texto contiguo.read -rlee la entrada y conserva las barras invertidas.- Los valores exportados se copian a los procesos hijos, nunca de vuelta a un proceso padre.
unsetelimina una variable.
2.2 Protege palabras, variables y caracteres especiales mediante comillas
Bash lee un comando antes de que el programa reciba sus argumentos. Los espacios separan palabras y caracteres como *, ?, $, ;, &, |, < y > tienen funciones especiales. La protección mediante comillas controla cuáles de esas funciones permanecen activas.
Elige qué debe expandirse
| Forma | Qué hace Bash |
|---|---|
'fixed text' | Mantiene como literal todo lo que contiene. |
"text with $name" | Conserva los espacios y caracteres comodín, pero expande variables, salidas de comandos y operaciones aritméticas. |
\* | Trata literalmente el siguiente carácter fuera de comillas. |
Con HOME=/home/sam, compara:
echo 'Home: $HOME *'
echo "Home: \$HOME *"
El primero muestra «Home: $HOME *». El segundo muestra «Home: /home/sam *». El asterisco permanece literal en ambos, pero solo las comillas dobles permiten que la variable se expanda. Una comilla simple no puede colocarse directamente dentro de una cadena protegida por comillas simples.
Dentro de comillas dobles, las barras invertidas pueden proteger un signo de dólar, un acento grave, una comilla doble o una barra invertida. Por ejemplo, echo "Price: \$5" muestra «Price: $5». Fuera de comillas, echo 5 \* 3 muestra «5 * 3» y touch my\ file.txt crea un archivo con un espacio en su nombre.
Sigue un valor sin comillas por Bash
file="my report.txt"
cp $file backup/
Primero Bash expande la variable. Después, la división en palabras divide su valor en espacios, tabulaciones y saltos de línea. El comando recibe my, report.txt y backup/ como argumentos separados. Intenta copiar dos archivos de origen en lugar del único archivo deseado.
Si una palabra resultante contiene caracteres comodín, la expansión de nombres de archivo la sustituye después por los nombres coincidentes. Un valor almacenado como *.txt puede convertirse en varios argumentos de archivo al expandirse sin comillas. Estos pasos adicionales ocurren antes de que comience cp; el programa no puede recuperar la agrupación que pretendías.
cp "$file" backup/
Ahora el valor expandido sigue siendo un argumento, «my report.txt». Bash elimina los propios caracteres de comillas; son instrucciones para el análisis, no parte de la ruta que se pasa a cp. Pon comillas dobles alrededor de las expansiones de variables y las sustituciones de comandos siempre que su valor completo deba permanecer unido.
Conserva un valor vacío
Las comillas también importan cuando un valor está vacío. En [ $answer = yes ], un answer vacío desaparece y deja una prueba no válida. [ "$answer" = yes ] pasa una cadena vacía como un argumento, por lo que la prueba es válida y falsa.
La misma regla de agrupación se aplica a palabras literales. mkdir new folder crea dos directorios, mientras que mkdir "new folder" crea uno. Proteger una ruta completa con comillas es útil tanto si su espacio se escribió directamente como si procede de una variable.
Combina texto literal y expandido
Las partes contiguas protegidas por comillas sin un espacio que las separe forman una sola palabra. Con price=8, echo 'Price: $'"$price" muestra «Price: $8». La parte fija está entre comillas simples y la parte variable entre comillas dobles. Un patrón de búsqueda también puede mantenerse fijo: grep 'cost: \$[0-9]' prices.txt pasa su patrón sin expansión por el intérprete de comandos y deja que grep lo interprete.
Puntos clave
- Las comillas simples mantienen el texto literal; las dobles permiten expansiones y mantienen unidos los valores.
- Las expansiones sin comillas pasan por la división en palabras y después por la expansión de nombres de archivo.
- Las comillas conservan un valor vacío como argumento.
- Una barra invertida puede hacer que un carácter especial se trate literalmente.
- Las partes contiguas protegidas por comillas forman una palabra cuando ningún espacio las separa.
2.3 Captura la salida de comandos y realiza cálculos con números enteros
Los comandos suelen producir un valor que necesita otro paso. Bash puede capturar esa salida, colocarla dentro de un texto o usarla en un cálculo. La sustitución de comandos y la expansión aritmética tienen una puntuación similar, pero realizan tareas distintas.
Captura la salida estándar
today=$(date +%F)
cp notes.txt "notes-${today}.txt"
$(...) ejecuta un comando y sustituye la expresión por su salida estándar. El 2026-10-22, today contiene «2026-10-22» y la copia se llama notes-2026-10-22.txt. Una fecha en orden año-mes-día mantiene los nombres de archivo ordenados por fecha cuando se ordenan por nombre. También puedes poner la sustitución directamente en el nombre: "notes-$(date +%F).txt".
Los caracteres de salto de línea finales se eliminan de la salida capturada. La forma más antigua con acentos graves también captura la salida, pero $(...) es más fácil de leer y anidar. Protege con comillas una sustitución usada como argumento de un comando, como "$(date +%F)", para mantener unido su resultado.
La sustitución de comandos captura solo la salida estándar. Los errores enviados a la salida de error estándar siguen yendo a su destino habitual. result=$(some_command 2>&1) combina ambos flujos dentro de la captura cuando eso es lo que necesita el guion. Mezclar errores en un valor destinado a contener un número haría fallar los cálculos posteriores.
Captura un recuento sin nombre de archivo
lines=$(wc -l < access.log)
echo "Lines: $lines"
Si el archivo contiene 342 caracteres de salto de línea, wc proporciona el recuento 342. Al redirigir el archivo a wc, su salida contiene solo el recuento; wc -l access.log también muestra el nombre del archivo. Un resultado que parece numérico puede reutilizarse después, siempre que el comando haya tenido éxito.
Calcula con números enteros
$(( ... )) realiza una expansión aritmética:
echo "$(( 17 / 5 ))"
echo "$(( 17 % 5 ))"
Los resultados son 3 y 2. La división entera descarta el resto; % lo devuelve. La suma, la resta y la multiplicación usan +, - y *. Los nombres de variables pueden aparecer sin signo de dólar dentro de la expresión: total=$(( price * qty )).
Con a=5, echo "$a+3" muestra «5+3» como texto. echo "$(( a + 3 ))" calcula y muestra 8. Los paréntesis adicionales seleccionan la aritmética; $(a + 3) intentaría ejecutar un comando llamado a.
Un contador comienza con un valor como count=0 y se actualiza con count=$(( count + 1 )). Bash también ofrece (( count++ )); este es un comando aritmético con su propio estado de salida, que importa en guiones que usan opciones de tratamiento de errores.
Conserva la precisión necesaria
La aritmética de Bash usa números enteros. 7 / 2 da 3 y un valor decimal como 2.5 provoca un error de sintaxis aritmética. Una herramienta independiente puede calcular decimales:
echo "scale=2; 7 / 2" | bc
Esto produce 3.50. En la aritmética entera, multiplica antes de dividir cuando el producto conserve una fracción que aún necesitas. Para 45 de 60, $(( 45 * 100 / 60 )) da 75. Dividir primero da cero para 45 / 60, por lo que $(( 45 / 60 * 100 )) sigue siendo cero; la fracción perdida no puede recuperarse mediante una multiplicación posterior.
Puntos clave
$(command)captura la salida estándar y elimina los saltos de línea finales.$((expression))calcula con números enteros.- Usa
/para la división entera y%para su resto. - Un contador almacena su valor actualizado después de cada incremento.
- Multiplicar antes de dividir puede evitar una pérdida temprana de precisión en la aritmética entera.
- Usa una herramienta como
bccuando se necesite un resultado decimal.
3Indica el éxito y el fallo mediante códigos de salida
Un guion necesita un resultado que tanto las personas como los programas puedan entender. La salida impresa explica lo que ocurrió, mientras que un estado de salida permite que otro comando decida si debe continuar. Guardarás ese estado, comprobarás los pasos dependientes y mantendrás visibles los fallos de las cadenas de comandos conectados por tuberías. Las comprobaciones de sintaxis, los trazados de ejecución y las opciones de tratamiento de errores ayudan a encontrar la causa de una ejecución fallida antes de que los comandos posteriores hagan más difíciles de ver sus efectos.
3.1 Lee y establece códigos de salida y encadena comandos según sus resultados
Un comando comunica su resultado de dos formas: puede mostrar texto y devuelve un estado de salida. Los programas usan ese estado para decidir qué ocurre después. Un guion puede mostrar un mensaje tranquilizador y aun así haber fallado, o no mostrar nada y tener éxito.
Lee un estado antes de que cambie
Un estado de salida es un número entero entre 0 y 255. Cero significa éxito. Un valor distinto de cero indica un fallo u otro resultado documentado. grep, por ejemplo, usa 0 para una coincidencia, 1 si no hay coincidencias y 2 para un error. Una búsqueda sin coincidencias puede ser un resultado normal para tu tarea aunque su estado sea distinto de cero.
$? contiene el estado del comando más reciente:
grep -q root /etc/passwd
status=$?
echo "Search status: $status"
La asignación guarda el resultado antes de que otro comando lo sustituya. En ls /missing; echo $?; echo $?, GNU ls devuelve 2 para la ruta inaccesible indicada en la línea de comandos. El primer echo muestra 2 y después termina correctamente. El segundo muestra 0, el estado de ese echo, no el del listado original.
Termina con un resultado útil
exit 1 termina inmediatamente un guion y comunica 1 a quien lo llamó. exit 0 comunica éxito. Un exit sin número usa el estado del comando anterior; llegar al final normalmente usa el estado del último comando. Elige códigos entre 0 y 255: exit 256 vuelve a 0 e indicaría incorrectamente que hubo éxito.
Algunos estados proceden del propio Bash:
| Código | Significado |
|---|---|
| 127 | No se encontró el comando. |
| 126 | Se encontró el comando, pero no se pudo ejecutar. |
128 + n | El comando terminó debido a la señal número n. |
Ctrl+C envía la señal 2, por lo que un comando terminado de esa forma suele comunicar 130. Los programas ordinarios también documentan sus propios códigos; 1 y 2 no tienen un significado universal para todas las herramientas.
Encadena comandos dependientes
mkdir -p ~/backup && cp notes.txt ~/backup/
cd /data/reports || exit 1
&& ejecuta el siguiente comando solo después de un éxito. Aquí la copia depende de crear o encontrar el directorio de copia de seguridad. || ejecuta el siguiente comando solo después de un fallo. Aquí, un cambio de directorio fallido detiene el guion antes de que los comandos posteriores usen el directorio de trabajo equivocado.
true devuelve 0; false devuelve 1. Un ! inicial invierte el éxito o el fallo de un comando. ! grep -q ERROR app.log tiene éxito cuando la búsqueda no encuentra ninguna línea coincidente, aunque también tiene éxito si grep falla con un error; usa comprobaciones explícitas del estado cuando debas distinguir esos resultados.
Comprueba una cadena de comandos completa
grep ERROR missing.log | wc -l
De forma predeterminada, una cadena de comandos conectados por tuberías tiene el estado de su último comando. grep falla porque falta el archivo, pero wc lee un flujo vacío, muestra 0 y tiene éxito. Por tanto, el estado de la cadena es 0.
set -o pipefail hace que una cadena falle cuando falle cualquiera de sus comandos. Devuelve el estado distinto de cero situado más a la derecha, o 0 si todos los comandos tienen éxito. Esto hace que los errores de los comandos anteriores sean visibles para if, &&, || y quien llamó al guion. Así, un programador de tareas puede distinguir un informe correcto de uno que nunca leyó su entrada.
Puntos clave
- El estado de salida 0 significa éxito; los resultados distintos de cero tienen significados documentados por cada programa.
- Guarda
$?inmediatamente si necesitas usarlo después de otro comando. exitproporciona un resultado a quien llamó al guion.&&continúa después de un éxito y||continúa después de un fallo.- Sin
pipefail, una cadena de comandos conectados por tuberías solo comunica el estado de su último comando.
3.2 Detecta errores y detén un guion de forma segura
Bash normalmente continúa después de que falle un comando. Si el siguiente comando depende de ese trabajo, continuar puede convertir un pequeño fallo en un problema mayor. Comprueba explícitamente los pasos de los que dependen otros y usa la comprobación de sintaxis y el trazado para averiguar por qué una ejecución se comporta de forma distinta a la prevista.
Detén el guion antes de que se propaguen los efectos de un fallo
cd /backups || exit 1
Ahora, los comandos posteriores solo pueden ejecutarse si el cambio de directorio tiene éxito. Esto importa antes de las operaciones con archivos: si falla un cambio de directorio y el guion continúa, las rutas relativas siguen apuntando al directorio anterior. Comprueba el destino antes de ejecutar comandos que modifiquen o eliminen archivos.
Un mensaje de error y un estado de fallo sirven a destinatarios distintos:
echo "Error: $file not found" >&2
exit 1
El mensaje va a la salida de error estándar, dejando la salida estándar disponible para los datos. Con ./report.sh > report.txt, el mensaje sigue siendo visible en el terminal mientras la salida normal entra en el archivo. El estado distinto de cero permite que otro programa detecte el error sin leer la frase.
Comprueba la sintaxis y después traza la ejecución
| Comando | Qué hace |
|---|---|
bash -n script.sh | Lee la sintaxis sin ejecutar comandos. |
bash -x script.sh | Ejecuta el guion y muestra los comandos expandidos antes de ejecutarlos. |
La ausencia de fi, done o una comilla de cierre es un problema de sintaxis. bash -n puede localizarlo, a menudo mediante un mensaje «unexpected end of file». Una ruta de archivo válida desde el punto de vista sintáctico, pero mal escrita, necesita una comprobación durante la ejecución.
El trazado antepone + a los comandos. Una línea como cp "$src" "$dest" revela las rutas reales que recibió. set -x y set +x activan y desactivan el trazado alrededor de una sección.
Comprende las opciones de tratamiento de errores
set -euo pipefail combina tres controles:
-etermina el guion después de un fallo de comando no tratado.-uinforma del uso de una variable no establecida como un error.pipefailhace que los comandos fallidos de una cadena conectada por tuberías afecten a su estado.
-e permite fallos esperados en las condiciones de if, while y until, en comandos negados y en comandos que no son los últimos de listas con && o ||. Sin pipefail, un fallo anterior al último comando de la cadena no provoca la salida. Las comprobaciones explícitas siguen siendo útiles porque indican qué debe hacer el guion cuando falla un paso concreto.
Un comando aritmético también comunica verdadero o falso. (( count++ )) devuelve el estado 1 cuando el valor anterior es 0, por lo que un uso no tratado con -e puede detener el guion aunque se haya producido el incremento. La asignación count=$(( count + 1 )) evita ese estado del comando aritmético.
-u detecta un error de escritura como $filname cuando solo se ha establecido filename. No rechaza una variable que existe pero está vacía. ${dir:?not set} comprueba si dir falta o está vacía en esa expansión. Un resultado esperado sin coincidencias puede gestionarse con una prueba; command || true suprime todos los fallos de ese comando, por lo que debes usarlo solo cuando todos esos fallos sean aceptables.
Lee los mensajes y limpia los archivos temporales
«Command not found» señala un problema con el nombre, el programa instalado o PATH. «Permission denied» señala un problema de ejecución o de acceso a un archivo. «Unary operator expected» suele deberse a un valor vacío sin comillas en [ ]; «integer expression expected» significa que una prueba numérica recibió texto.
Un manejador de eventos EXIT establece una limpieza, por ejemplo trap 'rm -f "$tmpfile"' EXIT, después de asignar tmpfile. El comando entre comillas se ejecuta cuando Bash termina, incluso con un exit explícito o una salida por error con -e. ShellCheck también puede inspeccionar guiones en busca de errores habituales de protección mediante comillas y de lógica antes de ejecutarlos.
Puntos clave
- Comprueba un paso antes de ejecutar comandos que dependan de él.
- Escribe los mensajes de diagnóstico en la salida de error estándar e indica el fallo con un estado distinto de cero.
bash -ncomprueba la sintaxis;bash -xejecuta y traza.set -etiene excepciones para los fallos que se comprueban.set -udetecta variables no establecidas, mientras que${name:?message}también rechaza valores vacíos.- Un manejador EXIT puede eliminar un archivo temporal cuando termina el guion.
4Toma decisiones y repite tareas
Un guion útil elige acciones y las repite sobre entradas cambiantes. Las pruebas convierten preguntas sobre archivos, texto y números en resultados de éxito o fallo. Las ramas seleccionan una acción, mientras que los bucles aplican comandos a listas o continúan hasta que cambia una condición. Seguirás el valor usado en cada iteración y conservarás espacios, registros y contadores a medida que los datos pasen por el guion.
4.1 Realiza pruebas con archivos, cadenas y números
Una condición en Bash es un comando cuyo estado significa verdadero o falso. Las pruebas permiten hacer preguntas sobre rutas, texto y números. Elige un operador para el tipo de valor que tienes; los mismos caracteres mostrados pueden tener distintos significados como texto y como número.
Separa los elementos de la prueba
test -f notes.txt y [ -f notes.txt ] preguntan si una ruta apunta a un archivo regular existente. [ es un comando y su último argumento debe ser ]. Los espacios separan sus argumentos:
[ -f "$file" ]
Sin el espacio después de [, Bash puede buscar un comando llamado [-f. En [ "$a"="$b" ], la falta de espacios alrededor de = forma una sola palabra no vacía, cuya prueba da verdadero aunque los valores sean distintos. Los operadores deben ser argumentos separados.
Elige una prueba de archivo
| Operador | Verdadero cuando la ruta… |
|---|---|
-e | Existe. |
-f | Es un archivo regular existente. |
-d | Es un directorio existente. |
-r, -w, -x | El usuario actual puede leerla, escribir en ella o ejecutarla, respectivamente. |
-s | Existe y tiene un tamaño mayor que cero. |
-L | Es un enlace simbólico. |
Para un directorio llamado logs, -e y -d tienen éxito, mientras que -f falla. Las pruebas de archivos normalmente siguen un enlace simbólico hasta su destino; -L comprueba el propio enlace. Por tanto, un enlace roto puede satisfacer -L y fallar en -e.
Compara texto o números enteros
Las pruebas de cadenas usan = y != para comprobar la igualdad y la desigualdad. -z comprueba si la longitud es cero y -n si es distinta de cero. [ "$answer" = yes ] coincide exactamente con «yes»; «Yes» y «yes » son textos distintos. Las comillas dobles mantienen un valor vacío en la prueba.
Las comparaciones de enteros usan -eq, -ne, -lt, -le, -gt y -ge: igual, distinto, menor que, menor o igual que, mayor que y mayor o igual que. [ "$count" -gt 100 ] pregunta si el número supera 100.
[ 07 -eq 7 ]
[ 07 = 7 ]
La comparación numérica tiene éxito porque los valores son iguales. La comparación de cadenas falla porque uno de los textos empieza con un cero adicional.
No uses > sin protección para una prueba numérica dentro de [ ]. En [ 10 > 9 ], Bash redirige la salida a un archivo llamado 9 y comprueba la palabra no vacía que queda. En [[ 10 < 9 ]] de Bash, el operador compara cadenas, por lo que el carácter inicial 1 se ordena antes que 9. Usa -lt o -gt para comparaciones numéricas, o aritmética de Bash como (( count > 100 )).
Combina condiciones
[ ! -d "$dir" ] tiene éxito cuando la ruta no es un directorio existente; puede ser un archivo regular o no existir. [ -f "$f" ] && [ -r "$f" ] tiene éxito solo cuando ambas pruebas tienen éxito. Las pruebas separadas y unidas por || tienen éxito cuando al menos una lo tiene.
Bash también tiene la palabra clave condicional [[ ... ]]. Evita la división en palabras de sus expansiones de variables y permite && y || en su interior. Un patrón sin comillas a la derecha de == busca coincidencias con el patrón: [[ $file == *.log ]] coincide con «app.log». Proteger ese patrón con comillas haría que se tratara literalmente. Esta sintaxis necesita Bash; dash no la implementa.
Puntos clave
- Una prueba indica verdadero con el estado 0 y falso con el estado 1.
- Pon espacios alrededor de
[y sus operadores, y cierra con]. - Las pruebas de archivos distinguen entre existencia, tipo y acceso.
- La igualdad de cadenas compara texto; los operadores numéricos comparan valores enteros.
- Usa
-gty-ltpara números, no símbolos de redirección sin protección. - La negación invierte una prueba;
&&requiere que se cumplan ambas condiciones. [[ ... ]]de Bash admite patrones y evita la división en palabras.
4.2 Elige acciones con if, elif, else y case
Las condiciones resultan útiles cuando seleccionan acciones. Un bloque if elige una rama a partir de los resultados de comandos. Un bloque case selecciona una rama comparando un valor con patrones. Ambos muestran las acciones disponibles en el guion.
Deja que un comando elija una rama
if grep -q ERROR app.log; then
echo "Errors found"
else
echo "No successful match"
fi
if ejecuta el comando y entra en la primera rama cuando devuelve 0. En caso contrario, entra en else. La propia búsqueda es la condición; no es necesario ejecutarla, mostrar algo y después examinar $?. Un error de grep también produce un valor distinto de cero, por lo que este ejemplo describe la rama else como ausencia de una coincidencia satisfactoria, no como prueba de que el archivo no contiene errores.
then debe comenzar un comando nuevo: colócalo en la línea siguiente o después de un punto y coma. fi cierra el bloque. La falta de fi suele producir un error de sintaxis al final del archivo porque Bash sigue esperando que se cierre el bloque.
Ordena las condiciones que se solapan
elif añade una prueba que se ejecuta solo cuando han fallado las pruebas anteriores. Para un porcentaje entero de uso del disco:
if [ "$usage" -ge 90 ]; then
echo "CRITICAL: disk ${usage}% full"
elif [ "$usage" -ge 75 ]; then
echo "WARNING: disk ${usage}% full"
else
echo "OK: disk ${usage}% full"
fi
Con usage=82, la primera prueba falla y la segunda tiene éxito, lo que produce «WARNING: disk 82% full». Con 95, se ejecuta la primera rama y se omite la rama de advertencia. Si la prueba de 75 fuera primero, 95 coincidiría con ella y nunca llegaría a la prueba crítica. Ordena los rangos que se solapan de modo que se compruebe la condición más restrictiva.
Solo se ejecuta la primera rama cuya prueba tiene éxito. else no necesita condición y se ocupa de los casos restantes. Se puede omitir elif o else cuando la tarea no lo necesite.
Compara un valor con case
case "$1" in
start) echo "Starting" ;;
stop) echo "Stopping" ;;
y|Y|yes) echo "Confirmed" ;;
*) echo "Usage: $0 start|stop|y|Y|yes" >&2; exit 2 ;;
esac
Cada patrón termina con ), cada rama termina con ;; y esac cierra el bloque. El | dentro de un patrón ofrece alternativas. El * final es el patrón de coincidencia universal y debe ir al final porque coincide con cualquier valor.
case usa patrones de nombres de archivo, no expresiones regulares. *.jpg coincide con un valor que termina en .jpg. [0-9]* coincide con un valor cuyo primer carácter es un dígito; el * puede coincidir después con cualquier texto, por lo que también coincide con «7draft». No demuestra que todo el valor contenga solo dígitos.
Elige la estructura adecuada
Usa case cuando una entrada, como un subcomando o una respuesta, tenga varias formas identificadas. Usa if cuando las condiciones examinen cosas distintas, como si existe un archivo y si un recuento supera un límite. Una coincidencia con un patrón se refiere a los caracteres de un valor; una prueba de archivo se refiere a la ruta en el disco. Un nombre terminado en .log puede coincidir con un patrón aunque no exista ningún archivo con ese nombre.
Puntos clave
ifelige una rama según el estado de salida de un comando; cualquier comando puede ser una condición.- Las pruebas
elifse ejecutan solo después de que fallen las condiciones anteriores. - Ordena los umbrales que se solapan del más restrictivo al más amplio.
caseselecciona el primer patrón coincidente y usa;;para terminar cada rama.- Una coincidencia con un patrón no demuestra que exista un archivo.
4.3 Repite comandos sobre listas y archivos con for
Un bucle for proporciona un nuevo valor al mismo cuerpo de comandos en cada iteración. La lista puede contener palabras literales, nombres de archivo coincidentes, un rango de números o los argumentos del guion. Bash asigna un elemento de la lista a la variable del bucle antes de ejecutar el cuerpo.
Recorre una lista fija
for host in web1 web2 db1; do
echo "Checking $host"
done
La primera iteración tiene host=web1, la segunda host=web2 y la tercera host=db1. El bucle muestra tres líneas. do abre el cuerpo y done lo cierra. La variable sigue disponible después del bucle y contiene el último valor asignado.
Un bucle también puede acumular un resultado:
total=0
for n in 4 8 15; do
total=$(( total + n ))
done
echo "$total"
El total almacenado cambia de 0 a 4, después a 12 y luego a 27. Inicializa el total antes del bucle para que la primera suma tenga un valor inicial definido.
Recorre los archivos coincidentes
for f in *.log; do
[ -f "$f" ] || continue
gzip -- "$f"
done
Bash expande el patrón en nombres coincidentes antes de ejecutar el cuerpo del bucle. Cada nombre de archivo coincidente sigue siendo un elemento de la lista, incluso si contiene espacios. Proteger "$f" con comillas dentro del cuerpo mantiene unido ese elemento cuando se pasa a gzip. Aquí, la prueba de archivo regular también omite los directorios cuyo nombre termina en .log.
Con la configuración predeterminada de expansión de nombres de archivo de Bash, un *.log sin coincidencias permanece literal. Un bucle sin una comprobación se ejecutaría una vez sobre los caracteres *.log y el comando fallaría. [ -e "$f" ] || continue omite las rutas inexistentes; usa -f cuando solo quieras archivos regulares.
No construyas un bucle de nombres de archivo a partir de $(ls). Su salida es texto, por lo que la división en palabras puede convertir «my report.txt» en dos elementos de la lista. Un patrón de nombres de archivo ya proporciona los nombres con sus límites intactos.
Crea un nombre nuevo a partir de cada nombre anterior
for f in *.jpeg; do
[ -f "$f" ] || continue
mv -- "$f" "${f%.jpeg}.jpg"
done
${f%.jpeg} elimina la terminación .jpeg del valor. Para «beach day.jpeg», el destino pasa a ser «beach day.jpg». Los dos argumentos protegidos con comillas mantienen intactas ambas rutas. -- indica a mv que los argumentos posteriores son nombres, incluso si uno empieza por -. Usa un directorio de destino sin nombres que entren en conflicto al probar el ejemplo, ya que mv puede reemplazar un destino existente.
Recorre un rango contando
for i in {1..5} proporciona del 1 al 5. Bash expande las llaves antes de expandir las variables, por lo que {1..$n} no produce un rango de longitud variable. Para un límite almacenado, usa la forma aritmética:
for (( i = 1; i <= n; i++ )); do
echo "$i"
done
La primera expresión inicializa el contador, la del medio lo comprueba antes de cada iteración y la última lo actualiza. for i in $(seq 1 "$n") también produce una lista de números para un límite entero positivo adecuado. La sustitución sin comillas es deliberada y proporciona números separados.
Para los argumentos, for arg in "$@" proporciona un elemento por cada argumento original. La forma más corta for arg; do significa lo mismo y también conserva los espacios dentro de cada argumento.
Puntos clave
- Un bucle
forejecuta su cuerpo una vez por cada elemento de la lista. - Los patrones proporcionan nombres de archivo completos; protege con comillas la variable del bucle en el cuerpo.
- Un patrón sin coincidencias permanece literal con la configuración predeterminada de Bash, así que comprueba los archivos en los bucles.
- Evita los bucles de nombres de archivo construidos a partir de
$(ls). - Los rangos entre llaves se fijan antes de expandir las variables; usa un bucle aritmético para un límite variable.
"$@"conserva los límites originales de los argumentos.
4.4 Repite tareas hasta que cambie una condición con while y until
Algunas repeticiones terminan cuando cambia una condición, no cuando se agota una lista. while y until comprueban la condición antes de cada iteración. El cuerpo de while se ejecuta mientras su condición tiene éxito; el de until se ejecuta mientras su condición falla. Cualquiera de los dos bucles puede ejecutarse cero veces.
Actualiza aquello de lo que depende la condición
i=1
while [ "$i" -le 3 ]; do
echo "Attempt $i"
i=$(( i + 1 ))
done
La condición primero encuentra 1, después 2 y luego 3. El cuerpo muestra esos tres números de intento y aumenta el contador cada vez. Después de actualizarlo a 4, la siguiente prueba falla y el bucle termina. Si faltara la actualización, i permanecería en 1 y el bucle seguiría ejecutándose. Ctrl+C detiene un bucle que se ejecuta en primer plano.
Para esperar a un archivo:
until [ -f /tmp/export.done ]; do
sleep 5
done
Si el archivo ya existe, el cuerpo del bucle nunca se ejecuta. En caso contrario, sleep 5 hace una pausa de cinco segundos antes de la siguiente comprobación. Una pausa evita que el bucle compruebe continuamente y desperdicie tiempo de procesador.
Lee los registros como líneas
while IFS= read -r line; do
echo "Host: $line"
done < hosts.txt
read proporciona una línea en cada iteración y devuelve un estado de fallo al final del archivo. IFS= conserva los espacios al principio y al final de la línea; -r conserva las barras invertidas. La redirección de entrada después de done proporciona datos a todo el bucle, no solo a su último comando.
Una línea como «web1 production» permanece como un solo valor. for line in $(cat hosts.txt) dividiría en espacios, tabulaciones y saltos de línea, tratando esas dos palabras como iteraciones separadas. Esa forma no puede conservar registros arbitrarios basados en líneas.
Conserva los cambios después del bucle
Una tubería que envía datos a un bucle, como cat hosts.txt | while read -r line; do ...; done, normalmente ejecuta el bucle en un proceso hijo en Bash. Un contador modificado allí se pierde para el proceso padre cuando termina el hijo. Redirige el archivo al bucle cuando los comandos posteriores necesiten sus valores acumulados:
count=0
while IFS= read -r line; do
count=$(( count + 1 ))
done < hosts.txt
echo "$count"
Esto procesa las líneas terminadas en un salto de línea y conserva el recuento actualizado en el intérprete de comandos actual. Ninguna cadena de comandos crea un proceso hijo para el bucle.
Gestiona el último registro y las salidas anticipadas
Un archivo puede terminar con texto pero sin un salto de línea final. read almacena ese último texto, pero indica un fallo, por lo que un while read simple no entra en su cuerpo para ese registro. Añade una segunda prueba para aceptar el texto no vacío almacenado:
while IFS= read -r line || [ -n "$line" ]; do
echo "Host: $line"
done < hosts.txt
break sale del bucle inmediatamente. continue omite los comandos restantes de la iteración actual y vuelve a comprobar la condición para la siguiente. Por tanto, un bucle while true necesita un break, un exit o una señal para terminar; puede servir para un menú que sale del bucle cuando la entrada es «q». En un bucle con contador, coloca una actualización antes de cualquier continue que de otro modo la omitiría, o esa iteración podría repetirse indefinidamente.
Puntos clave
whilerepite tras un éxito;untilrepite tras un fallo.- Ambos bucles comprueban la condición antes de entrar en sus cuerpos.
- Actualiza un contador o introduce una pausa en un bucle de comprobación para que avance sin esperar consumiendo recursos.
IFS= read -rconserva los espacios y las barras invertidas en la entrada basada en líneas.- Redirige un archivo al bucle para conservar las variables modificadas en el intérprete de comandos actual.
- Una prueba adicional de cadena no vacía conserva un registro final sin salto de línea.
breaksale de un bucle;continuepasa a su siguiente iteración.
5Pasa argumentos a los guiones
Los argumentos de la línea de comandos permiten que un guion sirva para muchas tareas sin editar su código. Leerás valores individuales, conservarás una lista completa de argumentos y procesarás las opciones iniciales. Antes de comenzar el trabajo, cuenta y valida las entradas, explica cómo llamar correctamente al guion y proporciona valores predeterminados para los valores opcionales. El resultado puede ejecutarse desde un indicador de comandos o sin supervisión, con mensajes claros y un estado de salida cuando la entrada no sea válida.
5.1 Lee los parámetros posicionales y el número de argumentos
Los argumentos convierten un guion con entrada fija en un comando reutilizable. Bash coloca las palabras que siguen al nombre del guion en parámetros posicionales. Sus límites los establece el intérprete de comandos que hace la llamada, por lo que las comillas importan tanto al llamar al guion como cuando este usa esos valores.
Identifica los parámetros
./backup.sh /home/sam/docs /mnt/usb
Dentro del guion, $0 es ./backup.sh, $1 es /home/sam/docs y $2 es /mnt/usb. $# es 2, el número de argumentos. El guion puede usar cp -r "$1" "$2" para copiar el directorio de origen al destino sin fijar ninguna de las dos rutas en el código.
$0 describe el nombre usado para iniciar el guion; no se cuenta en $#. Con ./greet.sh Ana "Lee Kim", el primer argumento es «Ana» y el segundo es «Lee Kim». Sin las comillas alrededor del segundo nombre, el guion recibiría tres argumentos.
Usa llaves después del noveno argumento
De $1 a $9 se nombran los primeros nueve parámetros posicionales. El décimo necesita ${10} y las posiciones posteriores siguen la misma forma. $10 significa la expansión de $1 seguida del carácter literal 0. Si el primer argumento es «Ana», $10 se convierte en «Ana0» incluso cuando existe un décimo argumento.
Un parámetro omitido se expande a texto vacío con la configuración normal. Con dos argumentos, falta $3; con set -u, expandirlo provoca un error de variable no establecida. Comprueba el número antes de leer las posiciones obligatorias o usa una expansión que proporcione un valor predeterminado.
Conserva todos los límites de los argumentos
Supón que un guion recibe "a b" y c. Compara:
| Expansión | Palabras que se pasan a otro comando |
|---|---|
"$@" | Dos: «a b» y «c». |
"$*" | Una: «a b c», con el separador habitual de espacio. |
$@ | Tres: «a», «b» y «c» con la división normal. |
"$@" es la opción habitual para pasar argumentos a otro comando:
for arg in "$@"; do
echo "Argument: $arg"
done
El bucle se ejecuta dos veces para esa llamada, una por cada argumento original. Sin argumentos se ejecuta cero veces. Poner "$@" entre comillas dobles tiene un significado especial: cada parámetro posicional sigue siendo una palabra separada, por lo que las comillas no unen toda la lista en una palabra.
"$*" une los valores usando el primer carácter de IFS, que normalmente es un espacio. Esto puede ser útil para una sola cadena destinada a mostrarse, pero pierde los límites individuales que puede necesitar un comando posterior.
Procesa parámetros con shift
shift elimina el primer parámetro posicional, desplaza los posteriores y reduce $#. En la llamada de copia de seguridad, un desplazamiento hace que $1 pase a ser /mnt/usb y que el recuento pase a ser 1. shift 2 elimina los dos primeros parámetros a la vez.
Esto permite crear un bucle que examine $1, lo procese y después desplace los parámetros antes de la siguiente iteración. Comprueba que queden argumentos con [ "$#" -gt 0 ]; de lo contrario, el guion puede leer un valor ausente o intentar desplazar más argumentos de los disponibles. El desplazamiento no cambia $0 ni puede cambiar la lista de argumentos del intérprete de comandos padre que inició el guion.
Puntos clave
$0es el nombre de invocación, mientras que$1y los siguientes contienen argumentos.$#cuenta los argumentos; los espacios protegidos por comillas se mantienen dentro de un argumento.- Usa
${10}para el décimo argumento;$10es$1seguido de0. "$@"conserva los argumentos por separado, mientras que"$*"los une.shiftelimina los parámetros iniciales y cambia las posiciones de los restantes.
5.2 Comprueba argumentos, muestra instrucciones de uso y establece valores predeterminados
Un guion debe asegurarse de que su entrada sea válida antes de empezar a trabajar. Comprueba el número de argumentos y después su significado. Las entradas opcionales pueden tener valores predeterminados; las entradas obligatorias ausentes necesitan un mensaje de diagnóstico claro y un estado de salida distinto de cero.
Explica la llamada esperada
if [ "$#" -ne 2 ]; then
echo "Usage: $0 SOURCE DEST" >&2
exit 2
fi
Esto comprueba el número antes de expandir $1 o $2, por lo que también funciona con set -u. El mensaje de uso va a la salida de error estándar. Las mayúsculas nombran valores que proporciona el usuario, [DEST] indicaría un destino opcional y FILE... significa uno o más argumentos de archivo. Una opción de ayuda como -h normalmente muestra las instrucciones de uso y termina con 0 porque pedir ayuda es un uso correcto.
El número de argumentos por sí solo no puede indicar si un origen es válido. [ -d "$1" ] comprueba si existe un directorio. Una prueba de archivo regular puede seleccionar archivos, pero la operación en sí sigue necesitando una comprobación del resultado: los permisos u otros errores pueden impedir la lectura.
Usa un valor predeterminado o exige un valor
logdir=${1:-/var/log}
src=${1:?Usage: backup.sh SOURCE [DEST]}
La primera forma usa /var/log cuando el primer parámetro falta o está vacío. La segunda detiene un guion no interactivo en cualquiera de los dos casos y muestra su mensaje en la salida de error estándar. Los dos puntos forman parte de ambas formas. Un valor predeterminado se usa para esta expansión; ${1:-...} no añade un argumento a la lista de parámetros posicionales.
Registra un fallo parcial
Un guion que cuenta líneas en archivos puede continuar después de una entrada incorrecta y aun así comunicar que la tarea completa quedó incompleta:
#!/bin/bash
if [ "$#" -eq 0 ]; then
echo "Usage: $0 FILE..." >&2
exit 2
fi
status=0
for f in "$@"; do
if [ -f "$f" ]; then
if lines=$(wc -l < "$f"); then
echo "$f: $lines lines"
else
echo "$f: could not count lines" >&2
status=1
fi
else
echo "$f: not a regular file" >&2
status=1
fi
done
exit "$status"
Para notes.txt missing.txt, el guion muestra el recuento del archivo legible e informa del archivo ausente y después termina con 1. La asignación se comprueba directamente, por lo que un fallo de lectura no se convierte en un recuento vacío considerado correcto. Un éxito posterior nunca restablece a 0 el indicador de fallo almacenado.
Gestiona opciones sencillas antes de los nombres de archivo
verbose=0
while [ "$#" -gt 0 ]; do
case "$1" in
-v) verbose=1; shift ;;
-h) echo "Usage: $0 [-v] FILE..."; exit 0 ;;
--) shift; break ;;
-*) echo "Unknown option: $1" >&2; exit 2 ;;
*) break ;;
esac
done
Cada opción reconocida se procesa y elimina con shift. El primer argumento ordinario termina el análisis de opciones; -- también lo termina y se elimina. El "$@" restante contiene los nombres de archivo, incluido un nombre que empiece por - después de --. getopts de Bash admite un análisis más completo de opciones cortas.
Un guion sin supervisión necesita obtener todas las entradas obligatorias de argumentos, valores predeterminados o configuración. read puede quedar bloqueado esperando un terminal o fallar inmediatamente al llegar al fin de archivo. Sustituir un argumento ausente por una indicación dejaría a una tarea programada sin una forma fiable de continuar.
Puntos clave
- Valida el número antes de expandir los argumentos obligatorios.
- Un mensaje de uso nombra las entradas obligatorias, opcionales y repetibles.
${1:-value}proporciona un valor predeterminado;${1:?message}rechaza un valor ausente o vacío.- Comprueba el resultado de la operación incluso después de comprobar el tipo de archivo de entrada.
- Conserva un estado de fallo general cuando continúes procesando varias entradas.
- Procesa las opciones con
shifty respeta--como final de las opciones.
6Programa la ejecución automática de guiones
Un guion sin supervisión necesita una programación y una forma de inspeccionar sus resultados. Cron expresa las horas coincidentes en una línea; systemd asocia un servicio con un temporizador. Leerás ambas formas, proporcionarás el entorno que necesita la tarea y mantendrás disponible su salida. Comprobar por separado la próxima activación y el resultado de la última tarea ayuda a distinguir una programación activa de un trabajo que realmente tuvo éxito.
6.1 Programa tareas con cron
Cron inicia comandos a las horas que coinciden con la programación. La tabla de cron de cada usuario guarda su programación y las tareas se ejecutan con su identidad. Un guion programado necesita tanto una expresión de tiempo correcta como un entorno que proporcione sus rutas, entradas y destino de salida.
Lee los cinco campos
Usa crontab -e para editar tu tabla y crontab -l para inspeccionarla. crontab -r elimina toda la tabla sin preguntar; usa el editor para eliminar una sola tarea.
| Campo, en orden | Valores |
|---|---|
| Minuto | 0–59 |
| Hora | 0–23 |
| Día del mes | 1–31 |
| Mes | 1–12 |
| Día de la semana | 0–7; 0 y 7 significan domingo |
30 2 * * * /home/sam/bin/backup.sh
Esto se ejecuta todos los días a las 02:30. Los asteriscos aceptan todos los valores de un campo. 0 9 * * 1-5 selecciona las 09:00 de lunes a viernes y 0 0 1 * * selecciona la medianoche del primer día de cada mes. Las horas usan la zona horaria del sistema salvo que la configuración de cron especifique otra zona admitida.
Combina rangos, listas e incrementos
Una coma enumera valores: 1,15 en el campo del día del mes selecciona el primero y el decimoquinto. Un guion indica un rango y / introduce un incremento. */15 en el campo de minutos selecciona 0, 15, 30 y 45.
*/20 8-10 * * * selecciona tres minutos en cada una de tres horas: nueve ejecuciones diarias, que comienzan a las 08:00 y terminan a las 10:40. Los incrementos vuelven a empezar dentro de su campo. */45 se ejecuta en el minuto 0 y el minuto 45 de cada hora; el intervalo hasta el minuto 0 de la hora siguiente es de solo 15 minutos.
Cuando tanto el día del mes como el día de la semana están restringidos, basta con que coincida cualquiera de los dos. 0 12 13 * 5 selecciona el mediodía del día 13 y de los viernes, no solo el viernes 13. Los demás campos también deben coincidir.
Las cadenas especiales sustituyen los cinco campos: @hourly, @daily, @weekly, @monthly, @yearly y @reboot. @daily significa medianoche, mientras que @reboot se ejecuta una vez al arrancar.
Proporciona rutas y conserva la salida
Cron normalmente usa /bin/sh para su línea de comandos, un PATH corto y ningún ajuste de inicio del intérprete de comandos interactivo. La propia línea de intérprete de Bash de un guion ejecutable sigue seleccionando Bash. Usa rutas absolutas para el guion y sus archivos, o establece PATH al principio de la tabla de cron.
30 2 * * * /home/sam/bin/backup.sh >> /home/sam/backup.log 2>&1
La tarea añade ambos flujos de salida al final del registro. Sin redirección, cron envía la salida por correo cuando está configurado, incluso mediante MAILTO; de lo contrario, la salida puede perderse. Un signo de porcentaje tiene una función especial en un comando de crontab: inicia un salto de línea y la entrada posterior. Escapa un formato de fecha en ese contexto, como en date +\%F. Un comando de fecha dentro de un guion separado usa el %F ordinario.
Distingue las programaciones del sistema y las tareas pendientes
/etc/crontab y los archivos de /etc/cron.d/ añaden un campo de usuario después de los cinco campos de tiempo. Por ejemplo, 30 2 * * * root /usr/local/bin/backup.sh se ejecuta como superusuario. No añadas ese campo de usuario a una tabla de cron personal.
Muchas distribuciones también ejecutan los archivos ejecutables que cumplen los requisitos en /etc/cron.daily/, /etc/cron.weekly/ y /etc/cron.monthly/. Las reglas predeterminadas de nombres de run-parts en Debian omiten los nombres que contienen puntos, así que usa allí backup-notes, no backup-notes.sh. Cron pierde las ejecuciones cuya hora pasa mientras el equipo está apagado. Anacron puede ejecutar tareas periódicas diarias, semanales o mensuales pendientes después del arranque.
Puntos clave
- Una tabla de cron personal tiene cinco campos de tiempo seguidos directamente de un comando.
- Las listas, los rangos y los incrementos seleccionan valores dentro de cada campo.
- Si los campos de día del mes y día de la semana están restringidos, basta con que coincida cualquiera de los dos.
- Usa rutas absolutas y un registro de salida para tareas sin supervisión.
- Escapa
%en un comando de crontab, incluidos los formatos de fecha. - Las tablas de cron del sistema añaden un campo de usuario; los directorios periódicos también aplican reglas para admitir archivos.
- Cron pierde las ejecuciones mientras la máquina está apagada; anacron permite ejecutar tareas periódicas pendientes.
6.2 Programa tareas con temporizadores de systemd
Systemd separa el trabajo de su programación. Una unidad de servicio describe el comando que se debe ejecutar. Una unidad de temporizador describe cuándo iniciarlo. De forma predeterminada, backup.timer activa backup.service, usando el nombre base compartido para conectar ambos.
Escribe el servicio y la programación de calendario
Coloca estas unidades del sistema en /etc/systemd/system/:
# backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Type=oneshot es adecuado para un guion que se ejecuta una vez y termina. Usa una ruta absoluta para el comando y haz que el guion sea ejecutable con una línea de intérprete de Bash. El temporizador proporciona la programación:
# backup.timer
[Unit]
Description=Run backup.service daily at 02:30
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
OnCalendar busca coincidencias con fechas y horas del reloj. Aquí, la fecha con comodines acepta todos los días. Persistent=true permite recuperar tareas pendientes después de que el temporizador haya estado inactivo: si se perdió al menos una ejecución de calendario, inicia el servicio una vez al reactivarse. No repite cada ejecución perdida.
Carga y activa el temporizador
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
Recarga las definiciones después de crear o cambiar archivos de unidad. enable --now inicia el temporizador inmediatamente y lo habilita para futuros arranques. Habilitar solo el servicio no crea una programación. Prueba el trabajo por separado con sudo systemctl start backup.service.
Elige entre hora del reloj y tiempo transcurrido
| Ajuste | Programación |
|---|---|
OnCalendar=Mon..Fri *-*-* 09:00:00 | De lunes a viernes a las 09:00 |
OnCalendar=*:0/15 | Minutos 0, 15, 30 y 45 de cada hora |
OnBootSec=10min | Diez minutos después del arranque |
OnUnitActiveSec=1h | Una hora después de la última activación del servicio |
Las expresiones de calendario pueden usar daily para la medianoche de cada día o weekly para el lunes a medianoche. Comprueba una expresión con systemd-analyze calendar "Mon..Fri 09:00" para ver su interpretación y su próxima ocurrencia.
Los dos últimos ajustes son temporizadores monotónicos: miden el tiempo transcurrido desde un evento. Combínalos para una primera ejecución después del arranque y activaciones posteriores cada hora. Persistent=true se aplica a los temporizadores de calendario; no añade la recuperación de ejecuciones de calendario a los temporizadores monotónicos.
Inspecciona por separado la programación y los resultados
systemctl list-timers muestra las próximas y las últimas activaciones. systemctl status backup.service muestra el resultado del servicio y journalctl -u backup.service muestra su salida y sus errores. Una próxima ejecución en la lista demuestra que una programación está activa, no que la tarea anterior del guion haya tenido éxito.
Los temporizadores tienen un margen de activación. AccuracySec tiene un valor predeterminado de un minuto; AccuracySec=1s reduce el margen de agrupación. RandomizedDelaySec añade deliberadamente un retraso aleatorio para distribuir el trabajo entre máquinas. Estos ajustes no garantizan un segundo de inicio exacto cuando hay carga.
Ejecuta un temporizador propio de usuario
Los archivos de unidad de usuario se guardan en ~/.config/systemd/user/ y los comandos usan systemctl --user, incluidos daemon-reload, enable --now y list-timers. Un gestor de usuario normalmente se ejecuta con la sesión de ese usuario. Un administrador puede habilitar la persistencia del gestor de usuario sin sesión abierta con loginctl enable-linger username para mantenerlo disponible sin iniciar sesión.
Cron necesita una línea de tiempo compacta y funciona sin systemd. Los temporizadores añaden un resultado de servicio y un registro, recuperación de ejecuciones de calendario y más control. Ninguno carga normalmente ~/.bashrc; ambos necesitan guiones que funcionen con rutas explícitas y sin indicaciones interactivas.
Puntos clave
- El servicio indica qué ejecutar; el temporizador indica cuándo.
- Recarga las unidades modificadas y habilita el
.timercon--now. - Los temporizadores de calendario siguen la hora del reloj; los monotónicos miden el tiempo desde eventos.
Persistent=trueejecuta una vez el trabajo de calendario pendiente al reactivarse.- Comprueba tanto la próxima activación del temporizador como el estado y el registro del servicio.
- Los temporizadores de usuario necesitan un gestor de usuario en ejecución, con persistencia habilitada para ejecutarse sin una sesión abierta.
Ejemplos de Guiones de Bash
1Guarda un informe de directorio repetible
9 pasos
- 1IntroducciónReúne una tarea repetida en un archivo
A menudo compruebas dónde estás, listas un directorio y muestras un mensaje de finalización. Guardar los comandos permite repetirlos en el mismo orden.
Un guion es un archivo de texto sin formato que lee un intérprete. Crearás un pequeño informe, seleccionarás Bash explícitamente y lo ejecutarás en un intérprete de comandos hijo. El nombre, el permiso de ejecución y la ubicación del archivo responden cada uno a una pregunta distinta sobre cómo iniciarlo.
- 2EjemploEscribe los comandos en orden
Guarda esto como
folder-report.shen un editor de texto sin formato:#!/bin/bash pwd ls echo "Report finished"La línea de intérprete selecciona Bash cuando el archivo se ejecuta directamente. El comentario explica la tarea, pero no se ejecuta. Después, Bash ejecuta
pwd,lsyechoen ese orden. La terminación.shayuda a reconocer el archivo; no selecciona el intérprete. - 3DesafíoComprueba qué selecciona el lenguaje
Un colega cambia la primera línea a
#!/bin/shy después añade[[ ... ]]. El archivo sigue terminando en.sh. ¿Por qué puede fallar?---reveal---
La línea de intérprete selecciona
sh, que puede serdashy no entender[[ ... ]]de Bash. La extensión no elige el lenguaje. Restablece una línea de intérprete de Bash para usar sus funciones, con#!al principio mismo de la primera línea. - 4ExplicaciónLee primero el archivo con Bash
Ejecuta
bash folder-report.sh. Esto inicia Bash y le pasa el archivo de guion legible; el guion no necesita permiso de ejecución. El intérprete elegido ya es Bash, por lo que la línea de intérprete no toma esa decisión.Deberías ver una ruta, un listado y el mensaje «Report finished». Las rutas relativas usadas por los comandos dentro del guion se resuelven desde su directorio de trabajo, no automáticamente desde el directorio del archivo de guion.
- 5EjemploPermite la ejecución directa
Añade permiso de ejecución para el propietario y ejecuta la ruta exacta:
chmod u+x folder-report.sh ./folder-report.sh./indica el directorio actual. La ejecución directa usa la línea de intérprete del archivo. Si el archivo es legible pero no ejecutable, el comandobashanterior puede funcionar mientras este falla con «Permission denied». El permiso y la selección del intérprete son partes separadas del inicio. - 6ConsejoEncuentra el guion por su nombre
Escribir
folder-report.shsin una barra pide a Bash que busque en PATH. El directorio actual normalmente no está en esa lista.Un directorio bin personal permite ejecutar el guion desde otros directorios cuando está en PATH. Inspecciona
echo "$PATH"y usacommand -v folder-report.shpara ver qué ejecutable selecciona ese nombre. Si una copia antigua aparece primero en PATH, editar una copia más nueva en otro lugar no cambiará lo que ejecuta ese nombre. - 7DesafíoMantén un cambio de directorio en el intérprete adecuado
El guion ahora comienza con
cd /var/log. Después de que termine./folder-report.sh, ¿se ha desplazado tu terminal allí? ¿Cómo podría desplazarlo un archivo de configuración?---reveal---
El guion ejecutado funciona en un intérprete de comandos hijo, por lo que su cambio de directorio no desplaza el terminal padre. Ejecutar un archivo con
source ./settings.shejecuta sus comandos en el intérprete actual y puede cambiar el directorio de esa sesión. Esta forma de ejecución usa el lenguaje del intérprete actual. - 8DesafíoDiagnostica el inicio antes de editar los comandos
Un informe legible funciona con
bash folder-report.sh. La ejecución directa informa «Permission denied» y escribir solo su nombre informa «command not found». ¿Qué dos problemas de inicio debes comprobar?---reveal---
Comprueba el permiso de ejecución del guion para la ejecución directa. Después comprueba PATH o usa su ruta explícita
./para localizarlo. Una línea de intérprete de Bash válida selecciona el intérprete, pero no puede conceder permisos ni colocar el archivo en PATH. - 9RepasoEl inicio implica varias decisiones separadas
El archivo contiene la secuencia de comandos. El intérprete lee su lenguaje, los permisos permiten la ejecución directa y PATH o una barra localizan el archivo.
Un guion ejecutado funciona en un intérprete de comandos hijo. Un archivo de configuración ejecutado con source funciona en el intérprete que ya está abierto, por lo que sus asignaciones y cambios de directorio pueden permanecer en esa sesión.
2Crea un nombre de informe con fecha sin perder espacios
11 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónSigue un valor hasta un comando
- 2EjemploAlmacena un destino de varias palabras
- 3ConexiónPasa el ajuste a un proceso hijo
- 4DesafíoSepara un nombre de su sufijo
- 5EjemploConserva la ruta almacenada
- 6DesafíoElige entre texto fijo y texto variable
- 7EjemploCaptura una fecha para el nombre
- 8EjemploCalcula antes de insertar el valor
- 9DesafíoLocaliza la fracción perdida
- 10DesafíoCombina la ruta y el valor capturado
- 11RepasoDistingue las tres funciones
3Evita que una búsqueda fallida se convierta en un informe satisfactorio
10 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónTrata el resultado como parte de la tarea
- 2EjemploDetecta el fallo oculto de un comando anterior
- 3Idea claveHaz que la cadena de comandos comunique su fallo
- 4DesafíoGuarda el estado que importa
- 5EjemploGestiona explícitamente el trabajo fallido
- 6ExplicaciónElige entre comprobación de sintaxis y trazado de ejecución
- 7ExplicaciónInterpreta las opciones de error como controles separados
- 8DesafíoExplica por qué continúa este guion
- 9DesafíoMantén informado a quien llamó al guion
- 10RepasoLee tanto los datos como el resultado
4Inspecciona los archivos entrantes y lee sus registros
15 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDeja que cada tipo de entrada elija su siguiente paso
- 2EjemploElige una prueba para el tipo de ruta
- 3ExplicaciónCompara los valores de la forma adecuada
- 4DesafíoInterpreta una prueba de archivo negada
- 5EjemploSelecciona una acción con el resultado de un comando
- 6DesafíoSigue umbrales que se solapan
- 7ExplicaciónCompara una palabra de acción con case
- 8EjemploProcesa un archivo por iteración con un patrón
- 9DesafíoExplica el caso de un directorio vacío
- 10ConsejoElige un límite numérico variable
- 11EjemploLee un registro sin dividirlo por sus espacios
- 12DesafíoConserva el último registro sin salto de línea
- 13ConexiónEspera sin comprobar continuamente
- 14DesafíoDiagnostica un total que permanece en cero
- 15RepasoAjusta la estructura a los datos
5Acepta archivos de entrada e informa de fallos parciales
10 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónHaz que la entrada forme parte de la llamada al comando
- 2EjemploInspecciona los límites de la llamada
- 3ExplicaciónProcesa la opción inicial
- 4DesafíoConserva un argumento vacío en el recuento
- 5EjemploRechaza una llamada sin archivos de entrada
- 6ExplicaciónElige un valor predeterminado solo para una entrada opcional
- 7EjemploComprueba la propia operación de lectura
- 8DesafíoRecuerda el fallo anterior
- 9DesafíoDetén el análisis antes de un nombre de archivo con guion
- 10RepasoDa a los comandos reutilizables un comportamiento fiable
6Programa un informe y verifica su última ejecución
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónPrograma solo tareas que tengan toda la entrada necesaria
- 2EjemploLee una entrada de una tabla de cron personal
- 3DesafíoSigue un incremento de minutos al cambiar de hora
- 4ConsejoDa a la tarea un destino de salida
- 5ConexiónDistingue una ejecución omitida de una fallida
- 6EjemploPon el trabajo en un servicio
- 7EjemploPon la hora en el temporizador correspondiente
- 8ExplicaciónCarga los cambios y habilita la programación
- 9DesafíoComprueba el resultado además de la próxima hora
- 10ExplicaciónCuenta el tiempo desde un evento cuando sea necesario
- 11DesafíoElige cómo recuperar tareas después de una interrupción
- 12RepasoInspecciona la programación y la tarea por separado
Ejercicios de Guiones de Bash
Set 1: Sigue valores, registros y programaciones10 Preguntas de Práctica
Pregunta 1 de 10
/bin/bash^M: bad interpreter, pero /bin/bash existe. ¿Qué cambio en el archivo resuelve el problema indicado?Mostrar respuestaOcultar respuesta
^M indica un retorno de carro de los finales de línea de Windows, que hace que la ruta del intérprete sea distinta de /bin/bash. Convertir el archivo a finales de línea de Unix elimina ese carácter adicional. El permiso de ejecución no puede corregir caracteres dentro de la ruta del intérprete y PATH no resuelve una ruta fija de la línea de intérprete.Pregunta 2 de 10
site?Mostrar respuestaOcultar respuesta
=. Las comillas conservan las dos palabras como valor. Con espacios alrededor de =, Bash trata site como un comando; sin comillas alrededor del valor, Hall pasa a ser una palabra de comando en lugar de parte de la asignación.Pregunta 3 de 10
left=$(( 29 % 6 ))?Mostrar respuestaOcultar respuesta
% devuelve ese resto. El cociente 4 se obtendría mediante división entera con /, mientras que la aritmética de Bash no produce un cociente decimal como 4,83 a partir de esta expresión.Pregunta 4 de 10
done de cierre. ¿Qué comando puede detectar ese problema de sintaxis sin ejecutar el guion?Mostrar respuestaOcultar respuesta
bash -n lee el guion y comprueba su estructura sin ejecutar los comandos. Puede detectar un bucle al que le falta el done de cierre. bash -x también lee el guion, pero lo ejecuta con trazado, por lo que los comandos válidos anteriores podrían ejecutarse antes de encontrar el problema de sintaxis.Pregunta 5 de 10
[ 06 = 6 ] y [ 06 -eq 6 ], en ese orden?Mostrar respuestaOcultar respuesta
Pregunta 6 de 10
a.csv y late batch.csv, ambos archivos regulares. ¿Qué valores se usan en for f in *.csv; do echo "$f"; done?Mostrar respuestaOcultar respuesta
"$f" con comillas en el cuerpo mantiene unido ese valor cuando se pasa a otro comando.Pregunta 7 de 10
Un archivo contiene oak, un salto de línea y después elm sin salto de línea final. ¿Qué recuento se muestra?
count=0
while IFS= read -r line; do
count=$(( count + 1 ))
done < trees.txt
echo "$count"
Mostrar respuestaOcultar respuesta
|| [ -n "$line" ] también procesaría el último registro y produciría 2.Pregunta 8 de 10
./task.sh -v "blue room" output.txt, el guion ejecuta shift. ¿Cuáles son ahora los valores de $1 y $#?Mostrar respuestaOcultar respuesta
shift procesa el primer argumento, «-v», y desplaza los dos argumentos restantes. El nombre entre comillas pasa a ser $1 y $# baja de 3 a 2. El espacio dentro del nombre permanece intacto; el desplazamiento no divide el texto ni elimina también el segundo argumento.Pregunta 9 de 10
*/25 10-12 * * * y cuándo es su última ejecución?Mostrar respuestaOcultar respuesta
Pregunta 10 de 10
inventory.timer?Mostrar respuestaOcultar respuesta
inventory.timer inicia inventory.service. El temporizador almacena la programación, mientras que el servicio define el trabajo. Añadir otra extensión al nombre completo del temporizador no identificaría la unidad correspondiente de forma predeterminada.Set 2: Sigue los datos a través de un guion completo10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
zone=west. El archivo settings.sh contiene solo zone=east. El terminal ejecuta bash settings.sh, después source ./settings.sh y luego bash -c 'echo "${zone:-unset}"'. La variable nunca se exportó. ¿Qué muestra el último comando?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
name=archive, ¿qué muestra echo "${name}_ready"?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
completed=18 y total=32. ¿Qué resultado entero produce $(( completed * 100 / total ))?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
El archivo absent.log no existe. ¿Qué estado de salida recibe quien llamó al guion?
#!/bin/bash
set -o pipefail
grep NOTICE absent.log | wc -l
status=$?
echo "Count ended"
exit "$status"
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
¿Qué muestra este guion?
set -e
false || echo "Handled"
echo "Next"
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
*) después de los patrones de acciones con nombre?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
El directorio actual contiene solo los archivos regulares draft one.jpeg, final.jpeg y notes.txt. ¿Cuál es la salida?
count=0
for f in *.jpeg; do
[ "$f" = final.jpeg ] && continue
echo "${f%.jpeg}.jpg"
count=$(( count + 1 ))
done
echo "$count"
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
until [ -f /tmp/upload.ready ]; do sleep 3; done. El archivo regular ya existe antes de que comience el bucle. ¿Cuántas veces se ejecuta el cuerpo?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
status=0. Una entrada incorrecta establece status=1 y una entrada posterior tiene éxito. ¿Qué final indica que la solicitud quedó incompleta?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 3: Lee y ejecuta pequeños guiones de Bash10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
[[ ... ]] de Bash, pero su primera línea es #!/bin/sh. En esta máquina, sh es dash. ¿Qué primera línea selecciona el intérprete deseado?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
label="west side", ¿qué argumentos formatea printf '<%s>\n' "$label"?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
file="shift notes.txt". ¿Cómo debe copiar ese único archivo al directorio existente saved?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
archive existe y es un directorio. ¿Cuáles son los resultados de [ -f archive ] y [ -d archive ], en ese orden?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
¿Qué muestra este código?
used=14
limit=20
percent=$(( used * 100 / limit ))
if [ "$percent" -ge 60 ]; then
used=$(( used + 2 ))
elif [ "$percent" -ge 70 ]; then
used=$(( used + 5 ))
fi
echo "$used"
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
./label.sh "East Wing" report.txt. ¿Cuáles son los valores de $# y $2?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
dir=${1:-/srv/logs}. Se llama con un argumento que es una cadena vacía entre comillas. ¿Qué valor se asigna?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
25 4 * * * /home/rae/bin/audit.sh?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 4: Diagnostica entradas, flujo de control y periodos de inactividad10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
weekly.sh a weekly, sin modificar su contenido ni sus permisos. ¿Qué efecto tiene perder la extensión en la elección del intérprete que hace Linux según la línea de intérprete?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
export REGION=north y después inicia un guion que asigna REGION=south y termina. ¿Qué valor permanece en el proceso padre?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
pattern="*.txt". ¿Qué argumento recibe touch "$pattern"?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
¿Qué ocurre en este guion no interactivo?
set -eu
dest=
if [ -z "$dest" ]; then
dest=${2:-/srv/archive}
fi
echo "$dest"
El guion recibe un solo argumento, input.txt.
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
La variable count contiene 10 y se puede escribir en el directorio actual, donde no hay ningún archivo llamado 4. ¿Qué ocurre?
if [ "$count" > 4 ]; then
echo "High"
else
echo "Low"
fi
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
case "$value" in [0-9]*) echo "Match" ;; *) echo "No" ;; esac. ¿Qué ocurre para value=8draft?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
¿Qué se muestra?
i=0
total=0
while [ "$i" -lt 4 ]; do
i=$(( i + 1 ))
[ "$i" -eq 2 ] && continue
total=$(( total + i ))
[ "$total" -gt 5 ] && break
done
echo "$i:$total"
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
-v, una cadena vacía entre comillas y "red room", en ese orden. Ejecuta shift y después for arg in "$@"; do echo "<$arg>"; done. ¿Qué se muestra?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
0 11 9 * 2 /home/rae/bin/check.sh en el cron ordinario?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Persistent=true. Pasan tres activaciones diarias mientras el equipo está apagado. ¿Qué recuperación organiza al reactivarse?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Set 5: Combina la protección mediante comillas, las comprobaciones de fallos y las entradas reutilizables10 Preguntas de Práctica
Guarda esta unidad para ver todas las respuestas y practicar cada set.
Pregunta 1 de 10
Un terminal de Bash está en /home/rae, con PATH /home/rae/bin:/usr/local/bin:/usr/bin:/bin. Existen guiones ejecutables de Bash llamados scan en ambos directorios bin y en el directorio actual. Cada uno contiene solo una línea de intérprete de Bash y cd /srv/cache; ese directorio existe y es accesible. ¿Qué archivo ejecuta el primer comando y qué rutas se muestran?
scan
pwd
source ./scan
pwd
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
a.txt y b.txt. Con la configuración predeterminada de división y expansión de nombres de archivo de Bash, ¿cuántos argumentos de datos formatea printf '<%s>\n' $value después de value="*.txt spare"?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
ready en la salida estándar y warning en la salida de error estándar y después termina correctamente. ¿Qué almacena message=$(the_command)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
¿Qué estado de salida recibe quien llamó al guion?
#!/bin/bash
false
saved=$?
true && echo "Handled"
exit $(( saved + 2 ))
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
set -u y ya ha asignado folder="". Debe detenerse con un mensaje de diagnóstico útil antes de usar un directorio ausente o vacío. ¿Qué expansión proporciona esa comprobación?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
"$text" tiene una longitud distinta de cero?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
limit=3, ¿qué valores muestra for i in {1..$limit}; do echo "$i"; done con la expansión ordinaria de Bash?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
¿Qué recuento se muestra con el comportamiento predeterminado de las cadenas conectadas por tuberías en Bash? El archivo contiene tres líneas terminadas en salto de línea.
count=5
cat tasks.txt | while IFS= read -r line; do
count=$(( count + 1 ))
done
count=$(( count + 2 ))
echo "$count"
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Un guion analiza sus entradas con este código y después requiere exactamente dos argumentos de archivo. Tras la llamada ./copy.sh -v -- "early notes.txt" -final.txt, ¿cuántos argumentos quedan y qué debe ocurrir a continuación?
while [ "$#" -gt 0 ]; do
case "$1" in
-v) verbose=1; shift ;;
--) shift; break ;;
-*) echo "Unknown option" >&2; exit 2 ;;
*) break ;;
esac
done
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
/home/rae/.local/bin. ¿Qué cambio resuelve la diferencia probable?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Anacron
Asignación
name=value, sin espacios alrededor del signo igual.name="Lee Kim" mantiene las dos palabras juntas como un valor almacenado.B
Bash
[[ ... ]] selecciona Bash en su línea de intérprete para que se entienda su sintaxis condicional.break
Bucle for o ciclo for
web1 web2 db1 ejecuta su cuerpo una vez por cada uno de los tres nombres de equipo.Bucle until
Bucle while
read llega al fin de archivo e informa de un fallo.C
case
Comentario
# al principio de una palabra fuera del texto protegido por comillas.# Keep a copy for recovery explica por qué se necesita la siguiente copia de archivo.Comillas dobles
echo "Home: $HOME *" permiten expandir la ruta del directorio personal y conservan el asterisco.Comillas simples
echo '$HOME' muestre los caracteres «$HOME» en lugar de una ruta de directorio personal.Comparación de cadenas
Comparación numérica
-eq y -gt, independientemente de la longitud de su texto.[ "$count" -ge 8 ] tiene éxito para un recuento almacenado de 12.Comprobación de sintaxis
bash -n detecta la ausencia de done antes de que el bucle pueda ejecutar comandos.Contador
count=0 puede aumentar una vez por cada línea que lee un bucle.continue
cron
D
División en palabras
cp.División entera
$(( 7 / 2 )) produzca 3 aunque el cociente exacto sea 3,5.E
Ejecución de un archivo en el intérprete actual
./settings.sh mediante source carga sus asignaciones de variables directamente en la sesión abierta de Bash.Ejecución en cortocircuito
&& o ||.cd /data || exit 1 detiene los comandos dependientes después de un cambio de directorio fallido.elif
Eliminación de sufijos
${f%.jpeg}.Entorno mínimo
errexit
set -e de Bash, que termina el guion ante fallos no tratados y permite determinadas situaciones en las que se comprueba el estado de un comando.if fallida seleccione su rama else en lugar de terminar el guion.Estado de salida
grep -q distingue entre una coincidencia, la ausencia de coincidencias y un problema al leer la entrada.Estado de salida de una cadena de comandos
pipefail cambie esa regla.grep falla, pero el wc siguiente cuenta correctamente una entrada vacía.exit
exit 2 después de un error de uso para que quien lo llamó reciba un resultado de fallo.Expansión aritmética
$(( ... )) e inserta el valor calculado en el comando."$(( count + 1 ))" en el siguiente recuento entero.Expansión de llaves
{1..5} antes de que Bash realice la expansión de variables en el comando.{1..$n} en un rango basado en el valor almacenado en n.Expansión de nombres de archivo
*.log en nombres de archivo coincidentes separados antes de que comience un bucle for.Expansión de variables
"${file}_old" en «report_old» cuando file contiene «report».Exportación
F
Fin de archivo
read de Bash informa de un fallo cuando encuentra esta condición.read informe de un fallo.Final de línea
^M.G
Guion del intérprete de comandos
I
IFS
read conserva los espacios en blanco iniciales y finales.IFS= read -r line conserva los espacios de los extremos de cada registro leído del archivo de entrada.Incremento de un campo de cron
*/45 en los minutos de cron selecciona 0 y 45, y después vuelve a empezar en 0 en la hora siguiente.Indicador de fallo
Intérprete
#!/usr/bin/python3 lee código Python en lugar de comandos de Bash.Iteración
L
Línea de intérprete
#! e indica el intérprete que Linux debe usar para ejecutar un guion.#!/bin/bash comienza en el primer carácter, antes de cualquier comentario o línea en blanco.M
Manejador de señales y eventos
Mensaje de uso
N
Negación
[ ! -d "$p" ] acepta tanto un archivo regular como una ruta que no existe.nounset
set -u de Bash, que trata la expansión de una variable no establecida como un error en un guion no interactivo.Número de argumentos
$#, sin incluir el nombre de invocación../greet.sh Ana "Lee Kim" porque el nombre entre comillas es un argumento.O
Opción
-v puede habilitar mensajes adicionales antes de que el guion procese los nombres de archivo restantes.P
Palabra clave condicional
[[ de Bash inicia una estructura de prueba del intérprete de comandos con sus propias reglas de análisis y búsqueda de coincidencias con patrones.[[ permite usar [[ $name == *.log ]] sin dividir el nombre en palabras.Parámetro posicional
$1; las posiciones posteriores a la novena requieren llaves.${10} recupera el décimo argumento sin añadir un cero a $1.Paso de argumentos a otro comando
"$@" para conservar cada límite."$@" mantiene una entrada vacía y un nombre de varias palabras como argumentos separados.PATH
job.sh en PATH, pero sigue la ruta explícita del directorio actual en ./job.sh.Patrón de coincidencia universal
* al final de un bloque case de Bash.*) informa de comandos desconocidos después de comprobar los subcomandos con nombre.Permiso de ejecución
chmod u+x job.sh permite que el propietario intente ejecutar ./job.sh.Persistencia del gestor de usuario sin sesión abierta
pipefail
grep puede hacer que falle toda la cadena de comandos.Proceso hijo
Protección mediante comillas
"$file" con comillas conserva «monthly report.txt» como un argumento al copiar el archivo.Prueba de archivo
[ -d "$src" ] acepta un directorio de origen, pero rechaza un archivo regular.R
Rama
read
read -r -p "Name: " name solicita un nombre y conserva las barras invertidas del texto introducido.Registro de systemd
journalctl -u backup.service muestra mensajes de la tarea de copia de seguridad.Resto o residuo
%.$(( 17 % 5 )) es 2 porque tres grupos completos de cinco usan 15.S
Salida de error estándar
>&2 permanece visible cuando la salida estándar va a un archivo.shift
-v, la siguiente palabra de la línea de comandos pasa a ser $1 para el analizador de opciones.Sustitución de comandos
$(command).today=$(date +%F) captura una fecha para usarla en el nombre de un archivo de copia de seguridad.T
Tabla de tareas de cron
crontab -l muestra la tabla de tareas de cron del usuario actual para que se puedan inspeccionar sus programaciones.Temporizador de calendario
OnCalendar=Mon..Fri 09:00 selecciona las mañanas de lunes a viernes a las 09:00.Temporizador monotónico
Trazado de ejecución
bash -x revela un argumento de origen vacío pasado a un comando de copia de archivos.U
Unidad de servicio
backup.service define el guion que activa el temporizador de copia de seguridad correspondiente.Unidad de temporizador
backup.timer establece la programación del servicio de copia de seguridad.V
Validación
Valor predeterminado
${1:-/var/log} para un argumento ausente o vacío.Variable
city almacena «Lisbon» después de city=Lisbon, por lo que echo "$city" puede mostrarlo.Variable de entorno
Sobre esta unidad
Crea tus propios Materiales de Estudio
Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.