1. Por qué importa en un script
En la terminal, cuando una línea no hace lo esperado, lo ves enseguida y la corriges. En un script, la misma línea se ejecuta con datos que no elegiste tú: un nombre de archivo con espacios, una variable que llegó vacía, un texto que contiene un asterisco. Y nadie está mirando. Fíjate en estas dos líneas, que se diferencian solo en un par de comillas:
$ archivo="informe final.txt"
$ rm $archivo
rm: cannot remove 'informe': No such file or directory
rm: cannot remove 'final.txt': No such file or directory
$ rm "$archivo" # borra el archivo correcto
En este caso no pasó nada grave, porque no existían archivos llamados informe ni final.txt. Si hubieran existido, la primera línea los habría borrado a ellos en lugar del que se quería. El comando rm no tiene la culpa: hizo exactamente lo que le pidieron. Lo que cambió es lo que recibió, y eso lo decidió Bash antes de ejecutarlo.
El tema 9 del curso de Terminal, Comodines, comillas y expansión, presentó estas transformaciones una por una. Aquí las ordenamos en un modelo completo, porque para escribir scripts confiables no basta con conocer cada pieza: hay que saber en qué orden ocurren, ya que ese orden explica casi todos los errores.
2. Un banco de pruebas: args
Para ver qué recibe un comando necesitamos uno que muestre sus argumentos, cada uno por separado y bien delimitado. echo no sirve, porque une sus argumentos con espacios y no se distingue si recibió una palabra o dos. Definamos una función que los cuente y los muestre entre ángulos:
$ args() { printf '%d argumentos:' "$#"; for a in "$@"; do printf ' <%s>' "$a"; done; echo; }
$ args uno dos tres
3 argumentos: <uno> <dos> <tres>
$ args "uno dos" tres
2 argumentos: <uno dos> <tres>
$ echo uno dos tres # echo oculta la diferencia
uno dos tres
No hace falta entender todavía cómo está escrita la función: $# es la cantidad de argumentos y "$@" son los argumentos mismos, que el bucle for recorre uno por uno; los veremos en los temas 18 y 20. La usaremos durante todo el tema. Si quieres tenerla siempre a mano, guárdala como script en ~/bin/args, con su línea shebang, tal como aprendiste en el tema 2.
3. El recorrido completo
Cada vez que Bash ejecuta una línea, sea escrita en la terminal o leída de un script, la procesa en ocho etapas, siempre en este orden:
| Etapa | Qué hace | Ejemplo |
|---|---|---|
| 1. Leer | Separa la línea en palabras y operadores, respetando las comillas. | ls -l "mis docs" | wc → ls, -l, "mis docs", |, wc |
| 2. Estructura | Reconoce comandos, tuberías, asignaciones y redirecciones. | Dos comandos unidos por una tubería. |
| 3. Llaves | Genera palabras a partir de listas y rangos. | f{1..3} → f1 f2 f3 |
| 4. Parámetros | Reemplaza la tilde, las variables, la aritmética y las sustituciones de comandos, de izquierda a derecha. | $HOME → /home/ana |
| 5. División | Vuelve a cortar en palabras los resultados de la etapa 4 que no estaban entre comillas. | $archivo → informe, final.txt |
| 6. Comodines | Reemplaza las palabras con *, ? o [ ] sin comillas por los nombres de archivo que coinciden. | *.txt → a.txt b.txt |
| 7. Comillas | Quita las comillas y barras invertidas que quedaron de la línea original. | "mis docs" → mis docs |
| 8. Ejecutar | Aplica las redirecciones y pone en marcha el comando con la lista final de palabras. | ls recibe -l y mis docs. |
Dos ideas de este cuadro son las que más pesan en la práctica, y las retomaremos varias veces. La primera: las etapas 5 y 6 se aplican a los resultados de la etapa 4. El contenido de una variable sin comillas se vuelve a cortar y se trata como comodín. La segunda: el orden es fijo, y una etapa no puede usar lo que produce otra posterior. Las llaves, por ejemplo, ocurren antes que las variables.
4. Etapa 1: palabras y operadores
Lo primero que hace Bash es cortar la línea en piezas. Corta donde encuentra un metacarácter: un espacio, un tabulador, un salto de línea, o uno de estos caracteres: | & ; ( ) < >. Los espacios solo separan y desaparecen; los demás forman operadores, como |, &&, ; o >>. Todo lo demás son palabras.
$ args uno;args dos # ; es un operador: no hace falta espacio
1 argumentos: <uno>
1 argumentos: <dos>
$ args a=b c-d e.f g/h # = - . / no cortan
4 argumentos: <a=b> <c-d> <e.f> <g/h>
$ args 'uno; dos' "tres | cuatro" # entre comillas, nada corta
2 argumentos: <uno; dos> <tres | cuatro>
En esta etapa las comillas ya cumplen su primera función: todo lo que está dentro de ellas forma parte de la misma palabra, aunque tenga espacios u operadores. Las comillas no desaparecen todavía: quedan marcadas, porque las etapas siguientes necesitan saber qué partes estaban protegidas.
También en esta etapa se reconocen los comentarios. Un # inicia un comentario solo si está al comienzo de una palabra:
$ args uno #dos tres
1 argumentos: <uno>
$ args uno#dos tres # dentro de una palabra, # es un carácter más
2 argumentos: <uno#dos> <tres>
5. Etapa 2: la estructura del comando
Con la línea ya cortada, Bash identifica qué papel cumple cada pieza. Tres reconocimientos de esta etapa explican errores frecuentes.
Las palabras reservadas
Palabras como if, then, for, do, done o while tienen un significado especial, pero solo en la posición de comando: al comienzo de la línea, o después de un operador como ; o &&. En cualquier otro lugar son palabras comunes. Por eso echo if then fi muestra esas tres palabras sin protestar, y por eso if y then necesitan un ; o un salto de línea entre ellos.
Las asignaciones
Una palabra de la forma nombre=valor en la posición de comando es una asignación, siempre que no haya espacios alrededor del =. Con espacios, la etapa 1 ya cortó la línea en tres palabras, y la primera se interpreta como el nombre de un comando:
$ destino=/respaldos # asignación
$ destino = /respaldos # el comando «destino» con dos argumentos
destino: command not found
$ destino= /respaldos # destino vacía, solo para ejecutar «/respaldos»
bash: /respaldos: Is a directory
El último caso es el más curioso. destino= es una asignación con valor vacío, y una asignación seguida de un comando no cambia la variable en la shell: la define solo para ese comando. Es la forma LANG=C sort archivo que viste en el tema 34 del curso de Terminal. Aquí, el «comando» resultó ser /respaldos.
Las redirecciones
Los operadores >, >>, <, 2> y sus parientes, con la palabra que los sigue, se separan del resto. No serán argumentos del comando: se aplicarán en la etapa 8. Por eso pueden escribirse en cualquier lugar de la línea, y estas dos son equivalentes:
$ args uno dos > salida.txt
$ > salida.txt args uno dos
$ cat salida.txt
2 argumentos: <uno> <dos>
6. Etapa 3: las llaves
La expansión de llaves genera texto: {a,b,c} produce tres palabras, y {1..5}, un rango. Es la primera de las expansiones, y la única que no sabe nada de variables ni de archivos: trabaja solo con el texto escrito.
$ args informe.{txt,pdf}
2 argumentos: <informe.txt> <informe.pdf>
$ args dia{01..03}
3 argumentos: <dia01> <dia02> <dia03>
$ cp config.ini{,.bak} # cp config.ini config.ini.bak
Que ocurra antes que todas las demás tiene una consecuencia que sorprende a todo el mundo alguna vez: un rango con una variable no funciona.
$ n=3
$ args {1..$n}
1 argumentos: <{1..3}>
En la etapa 3, Bash ve {1..$n}. Como $n todavía no es un número, no es un rango válido, y lo deja como está. En la etapa 4 se reemplaza $n, y queda el texto {1..3}, pero las llaves ya pasaron y no se vuelven a procesar. Para recorrer un rango variable se usa seq 1 "$n" o un bucle for al estilo C, que veremos en el tema 14.
7. Etapa 4: tilde, variables, aritmética y sustitución
Esta etapa agrupa cuatro expansiones que ocurren juntas, de izquierda a derecha a lo largo de cada palabra. Son las que introducen datos en la línea: el valor de una variable, el resultado de un cálculo, la salida de un comando.
| Expansión | Forma | Resultado | Tema |
|---|---|---|---|
| Tilde | ~, ~/docs, ~maria | El directorio personal, propio o de otro usuario. | — |
| Parámetros | $var, ${var}, $1, ${var:-otro} | El valor de una variable o de un argumento, con posibles transformaciones. | 5, 6 y 20 |
| Aritmética | $(( 2 + 3 * 4 )) | El resultado del cálculo: 14. | 7 |
| Sustitución de comandos | $(date +%F) | La salida del comando, sin los saltos de línea finales. | 5 |
$ args ~ "$HOME" $(( 60 * 24 )) "$(date +%F)"
4 argumentos: </home/ana> </home/ana> <1440> <2026-10-14>
$ args "~/docs" '$HOME' # entre comillas, la tilde no se expande
2 argumentos: <~/docs> <$HOME>
La tilde tiene una regla propia: solo se expande sin comillas y al comienzo de una palabra, o después de = o : en una asignación. Por eso destino=~/respaldos funciona, pero destino="~/respaldos" guarda literalmente la virgulilla, y un cd "$destino" posterior fallará con No such file or directory. Dentro de comillas se usa "$HOME/respaldos".
Lo importante de esta etapa es lo que no hace: el valor que inserta no se vuelve a analizar como código. Si una variable contiene $HOME, un ; o un |, esos caracteres llegan al comando como texto, sin ningún significado especial. Las comillas guardadas dentro de una variable, tampoco:
$ texto='hola; echo $HOME | wc'
$ args $texto
5 argumentos: <hola;> <echo> <$HOME> <|> <wc>
El ; y el | no separaron comandos, y $HOME no se expandió, porque la etapa 1, donde se reconocen los operadores, ya había pasado. Lo único que sí le ocurrió al valor fue la división en palabras de la etapa siguiente. Esa es la buena noticia: los datos no se convierten en código por accidente. La mala noticia viene ahora.
8. Etapa 5: la división en palabras
La división en palabras (word splitting) es la etapa en que Bash vuelve a cortar en palabras el resultado de las expansiones de la etapa 4 que no estaban entre comillas. Corta por los caracteres de la variable IFS, que por defecto son el espacio, el tabulador y el salto de línea.
Tres precisiones definen exactamente su alcance:
- Solo afecta a resultados de expansiones. El texto escrito literalmente en la línea ya se cortó en la etapa 1 y no se vuelve a cortar.
- Solo afecta a expansiones sin comillas dobles.
"$var"produce siempre exactamente una palabra. - Las secuencias de espacios cuentan como un solo separador, y los espacios al principio y al final desaparecen.
$ nombre=" Ana María Pérez "
$ args $nombre
3 argumentos: <Ana> <María> <Pérez>
$ args "$nombre"
1 argumentos: < Ana María Pérez >
$ args $(printf 'linea uno\nlinea dos') # también la salida de un comando
4 argumentos: <linea> <uno> <linea> <dos>
El caso más traicionero es el de la variable vacía. Sin comillas, una variable vacía no produce una palabra vacía: no produce nada, y el comando recibe un argumento menos de los que el script esperaba.
$ vacia=""
$ args $vacia
0 argumentos:
$ args "$vacia"
1 argumentos: <>
$ [ $vacia = "si" ] && echo coincide # el comando recibe: [ = si ]
bash: [: =: unary operator expected
La división en palabras tiene una sola utilidad legítima: convertir deliberadamente un texto con espacios en varios argumentos. Casi nunca es lo que se quiere, y en los scripts modernos ese trabajo lo hacen los arrays (tema 8). El ejemplo que lo muestra mejor es el intento de guardar opciones en una variable:
$ opciones='-l "mis documentos"'
$ args $opciones
3 argumentos: <-l> <"mis> <documentos">
Las comillas que están dentro del valor son datos, no sintaxis: se reconocerían en la etapa 1, que ya pasó. La división corta por los espacios y deja las comillas pegadas a los pedazos. No existe forma de escribir el valor para que funcione; la solución es un array, y la veremos en el tema 8.
9. Etapa 6: los nombres de archivo
Después de la división, cada palabra que contenga *, ? o [ sin comillas se trata como un patrón y se reemplaza por la lista de archivos que coinciden, en orden alfabético. Como en la etapa anterior, esto incluye a las palabras que salieron de una variable sin comillas:
informe.txt y notas.txt$ args *.txt
2 argumentos: <informe.txt> <notas.txt>
$ nota="Total: 3 * 4"
$ echo $nota
Total: 3 informe.txt notas.txt 4
$ echo "$nota"
Total: 3 * 4
El echo $nota es un error silencioso típico: el resultado depende de qué archivos haya en el directorio donde se ejecuta el script. En el tuyo funciona; en el servidor muestra una lista de archivos.
La otra regla que conviene recordar es qué pasa cuando un patrón no coincide con nada: Bash lo deja tal cual, con el asterisco incluido.
$ args *.pdf
1 argumentos: <*.pdf>
$ gzip *.pdf
gzip: *.pdf: No such file or directory
En la terminal es apenas un mensaje. En un script, un bucle que recorre *.log en un directorio vacío ejecuta una vez su cuerpo con el nombre *.log, literalmente. Por eso el script del tema 1 tenía la línea [[ -e "$archivo" ]] || continue. Bash ofrece una opción, shopt -s nullglob, que hace que un patrón sin coincidencias desaparezca; la usaremos en el tema 14.
10. Etapa 7: la eliminación de comillas
Las comillas y barras invertidas de la línea original cumplieron su función en las etapas anteriores: agrupar palabras y proteger de las expansiones. En la etapa 7 se eliminan, y el comando nunca las ve. Por eso partes con distinto tipo de comillas, escritas juntas, forman una sola palabra:
$ args "a"'b'\c
1 argumentos: <abc>
$ args "Hola, $USER"'. Saldo: $0'
1 argumentos: <Hola, ana. Saldo: $0>
$ args "" # una palabra vacía, explícita
1 argumentos: <>
Solo se eliminan las comillas que venían escritas en la línea. Las que llegaron dentro del valor de una variable, como en el ejemplo de opciones, son datos y se conservan.
11. Etapa 8: redirigir y ejecutar
Con la lista final de palabras, Bash hace dos cosas. Primero aplica las redirecciones, de izquierda a derecha. La palabra que sigue a un > también pasó por las expansiones, pero debe dar exactamente un nombre de archivo; si la división la parte en dos, Bash se niega:
$ salida="mi informe.txt"
$ echo hola > $salida
bash: $salida: ambiguous redirect
$ echo hola > "$salida" # correcto
Que se apliquen de izquierda a derecha explica por qué importa el orden de 2>&1, como viste en el curso de Terminal: cmd > log 2>&1 manda las dos salidas al archivo, mientras que cmd 2>&1 > log manda los errores a donde iba la salida antes de redirigirla, es decir, a la pantalla.
Después, Bash toma la primera palabra como nombre del comando y lo busca en este orden: una función con ese nombre, un comando interno, y por último un programa en los directorios de PATH. El resto de las palabras son sus argumentos. Desde este momento, el trabajo de Bash terminó: el comando recibe una lista de cadenas y no sabe nada de comillas, variables ni comodines.
12. Una línea, de principio a fin
Sigamos una línea realista por todas las etapas. Es parte de un script de respaldo, con estas variables y archivos:
nombre="proyecto"
registro="/tmp/registro respaldo.log"
# en el directorio actual hay: docs/ fotos/ app.conf red.conf
tar -czf ~/respaldos/$nombre-$(date +%F).tgz {docs,fotos} *.conf > "$registro" 2>&1
| Etapa | Qué ocurre |
|---|---|
| 1. Leer | Palabras: tar, -czf, ~/respaldos/$nombre-$(date +%F).tgz, {docs,fotos}, *.conf. Operadores de redirección: > "$registro" y 2>&1. El espacio dentro de $(date +%F) no corta, porque está dentro de la sustitución. |
| 2. Estructura | Un comando simple, tar, con dos redirecciones que se guardan para la etapa 8. |
| 3. Llaves | {docs,fotos} → docs fotos. |
| 4. Parámetros | ~ → /home/ana; $nombre → proyecto; $(date +%F) → 2026-10-14. En la redirección, "$registro" → "/tmp/registro respaldo.log". |
| 5. División | /home/ana/respaldos/proyecto-2026-10-14.tgz no tiene espacios: sigue siendo una palabra. $registro estaba entre comillas: no se divide. |
| 6. Comodines | *.conf → app.conf red.conf. |
| 7. Comillas | Se quitan las de "$registro": queda /tmp/registro respaldo.log, una sola palabra. |
| 8. Ejecutar | La salida estándar va a /tmp/registro respaldo.log y los errores al mismo lugar. Se ejecuta tar. |
Lo que tar recibe, finalmente, son seis argumentos:
<-czf> </home/ana/respaldos/proyecto-2026-10-14.tgz> <docs> <fotos> <app.conf> <red.conf>
La línea funciona, pero tiene una fragilidad. Supón que mañana alguien cambia la primera línea a nombre="mi proyecto". En la etapa 5, la ruta del archivo se parte en dos: /home/ana/respaldos/mi y proyecto-2026-10-14.tgz. tar crea un archivo llamado mi e intenta incluir en él un archivo inexistente. La corrección es entrecomillar la expansión; como la tilde no se expande entre comillas, se usa $HOME:
tar -czf "$HOME/respaldos/$nombre-$(date +%F).tgz" {docs,fotos} *.conf > "$registro" 2>&1
Las llaves y el *.conf quedan sin comillas a propósito: ahí sí queremos que Bash genere varias palabras.
13. Qué protege cada tipo de comillas
Con el modelo de las ocho etapas, cada forma de entrecomillar se describe con precisión por las etapas que desactiva:
| Etapa | Sin comillas | Comillas dobles "…" | Comillas simples '…' |
|---|---|---|---|
| 1. Espacios y operadores cortan | Sí | No | No |
| 3. Llaves | Sí | No | No |
| 4. Tilde | Sí | No | No |
4. $var, $(( )), $( ) | Sí | Sí | No |
| 5. División en palabras | Sí | No | No |
| 6. Comodines | Sí | No | No |
La columna central es la que hace a las comillas dobles tan útiles en un script: dejan entrar los datos (variables y sustituciones) pero impiden que esos datos se dividan o se expandan como comodines. Las comillas simples lo bloquean todo, y sirven para texto literal: patrones de grep, programas de awk, mensajes con signos de dólar.
Dentro de las comillas dobles, cuatro caracteres siguen siendo especiales: $, la comilla invertida `, la barra invertida \ cuando precede a uno de ellos o a ", y el propio ". Para incluir una comilla doble se escribe \"; para un dólar literal, \$. Dentro de comillas simples no hay forma de incluir una comilla simple: se cierra, se escribe \' y se vuelve a abrir, como en 'It'\''s'.
$'…'
Bash tiene unas comillas especiales, $'…', que se comportan como las simples pero interpretan secuencias de escape como \n (salto de línea), \t (tabulador) o \'. Son útiles para escribir caracteres invisibles: IFS=$'\n' asigna a IFS solo el salto de línea. Las usaremos en el tema 16.
14. Ver lo que Bash hace: set -x
No hace falta deducir de memoria qué recibió cada comando. La opción -x hace que Bash muestre cada comando después de todas las expansiones, justo antes de ejecutarlo, precedido de un +. Cuando un argumento contiene espacios o caracteres especiales, lo muestra entre comillas simples, para que se vea dónde empieza y dónde termina:
$ destino="/home/ana/mis respaldos"
$ set -x # activar la traza
$ cp ~/docs/{informe,notas}.txt "$destino"
+ cp /home/ana/docs/informe.txt /home/ana/docs/notas.txt '/home/ana/mis respaldos'
$ cp ~/docs/informe.txt $destino
+ cp /home/ana/docs/informe.txt /home/ana/mis respaldos
cp: target 'respaldos': No such file or directory
$ set +x # desactivarla
En la segunda traza se ve el problema sin necesidad de razonarlo: la ruta aparece sin comillas, partida en dos, y cp interpretó la última palabra como destino. Para un script entero, se ejecuta con bash -x script.sh, o se escribe set -x en la parte que se quiere observar. El tema 26 trata la depuración en detalle.
15. Errores clásicos, explicados
Con el modelo completo, los errores más comunes de los scripts dejan de ser misterios. Cada uno ocurre en una etapa concreta:
| Línea | Síntoma | Etapa | Corrección |
|---|---|---|---|
rm $archivo | Con espacios en el nombre, borra otros archivos o falla. | 5 | rm -- "$archivo" |
[ $resp = si ] | unary operator expected si la variable está vacía. | 5 | [ "$resp" = si ], o [[ $resp = si ]] |
echo $mensaje | Aparece una lista de archivos donde había un *. | 6 | echo "$mensaje" |
for f in $(ls) | Los nombres con espacios se parten en varios. | 5 | for f in * |
for f in *.log | Sin archivos, el bucle recibe el texto *.log. | 6 | [[ -e $f ]] || continue, o nullglob |
echo {1..$n} | Muestra {1..5} literalmente. | 3 | seq 1 "$n" |
dir="~/datos" | cd "$dir" no encuentra el directorio. | 4 | dir="$HOME/datos" |
total = 0 | total: command not found | 1 | total=0 |
if [$x -gt 0] | [5: command not found | 1 | if [ "$x" -gt 0 ]: los corchetes necesitan espacios. |
echo hola > $salida | ambiguous redirect | 5 y 8 | > "$salida" |
cmd $opciones | Las comillas guardadas en la variable llegan al comando. | 5 y 7 | Un array: cmd "${opciones[@]}" (tema 8) |
El error de if [$x -gt 0] merece un comentario: [ no es un signo de puntuación, sino un comando, otro nombre de test. Como cualquier comando, se separa de sus argumentos con espacios. Sin el espacio, la etapa 1 produce la palabra [$x, que tras la expansión es [5, y Bash busca un programa con ese nombre. Lo veremos en el tema 11.
16. La regla de oro
De todo lo anterior se desprende una regla sencilla, que evita la mayoría de los errores de esta tabla:
Escribe siempre "$var", "${var}", "$(comando)" y "$@" entre comillas dobles, salvo que quieras, a propósito, que el resultado se divida en palabras o se expanda como comodín. Lo excepcional debe ser la falta de comillas, y cuando ocurra, conviene que un comentario explique por qué.
Hay lugares donde Bash no aplica la división en palabras ni los comodines, y por eso las comillas no son necesarias: el lado derecho de una asignación (copia=$original), el interior de [[ ]] y la palabra de un case. Ponerlas igual no hace daño, y muchos prefieren hacerlo para no tener que recordar las excepciones. Lo que nunca se entrecomilla es lo que debe expandirse como patrón: *.txt, {a,b}, ~.
Esta regla tiene un aliado: ShellCheck, que presentamos en el tema 1, señala cada expansión sin comillas con el aviso SC2086: Double quote to prevent globbing and word splitting. Es, con diferencia, el aviso que más vas a ver, y el tema 4 lo pone a trabajar.
17. Resumen
- Bash procesa cada línea en ocho etapas fijas: leer, reconocer la estructura, llaves, parámetros, división en palabras, comodines, eliminación de comillas y ejecución.
- En la etapa 1 se corta la línea por espacios y metacaracteres; las comillas mantienen unido su contenido. Un
#al comienzo de una palabra inicia un comentario. - Las palabras reservadas solo cuentan en la posición de comando.
nombre=valores una asignación solo si no hay espacios alrededor del=. - Las llaves se expanden primero, antes que las variables:
{1..$n}no funciona. - La etapa 4 reemplaza tilde, variables, aritmética y sustituciones de comandos. Su resultado es texto: no se vuelve a interpretar como código.
- La división en palabras corta, por los caracteres de
IFS, los resultados de expansiones sin comillas. Una variable vacía sin comillas desaparece. - Después, las palabras con
*,?o[sin comillas se reemplazan por nombres de archivo. Un patrón sin coincidencias queda tal cual. - Las comillas escritas en la línea se eliminan al final; las que están dentro del valor de una variable son datos.
- Las redirecciones se aplican de izquierda a derecha, y su destino debe ser una sola palabra.
- Las comillas dobles permiten las expansiones de la etapa 4 y bloquean la división y los comodines. Las simples lo bloquean todo.
set -xybash -xmuestran cada comando tal como lo recibe el programa, después de todas las expansiones.- La regla de oro: entrecomillar toda expansión, salvo que se quiera a propósito dividir o expandir.
18. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta. La función args de la sección 2 te permite comprobar tus respuestas.
1. ¿Por qué echo no sirve para saber cuántos argumentos recibe un comando?
Porque muestra sus argumentos unidos por un espacio. Una palabra con un espacio dentro y dos palabras separadas se ven exactamente igual.
2. ¿Cuál es el orden de las expansiones?
Llaves; luego tilde, parámetros y variables, aritmética y sustitución de comandos (juntas, de izquierda a derecha); luego división en palabras; luego nombres de archivo. Al final, la eliminación de comillas.
3. ¿Qué recibe args en args a#b #c?
Un solo argumento, a#b. El primer # está dentro de una palabra y es un carácter común; el segundo está al comienzo de una palabra e inicia un comentario.
4. ¿Qué ocurre al ejecutar contador = 5, y por qué?
La etapa 1 corta la línea en tres palabras, y la primera, contador, se toma como nombre de un comando. La respuesta es contador: command not found. Una asignación no admite espacios alrededor del =.
5. Con n=4, ¿por qué echo {1..$n} no muestra 1 2 3 4?
Porque la expansión de llaves ocurre antes que la de variables. En ese momento el texto es {1..$n}, que no es un rango válido, y queda sin cambios. Cuando luego se reemplaza $n, las llaves ya no se procesan.
6. ¿Cuántos argumentos recibe args $v si v=" a b "? ¿Y args "$v"?
Sin comillas, dos: a y b; los espacios repetidos y los de los extremos desaparecen. Con comillas, uno: < a b >, con todos sus espacios.
7. ¿Por qué [ $resp = si ] da unary operator expected cuando resp está vacía?
Porque una variable vacía sin comillas no produce ningún argumento. El comando [ recibe = si ], y encuentra un operador donde esperaba un valor. Con "$resp" recibe una cadena vacía y la comparación funciona.
8. Si texto='a; ls', ¿ejecuta ls la línea echo $texto?
No. El ; solo funciona como operador si aparece en la etapa 1. Cuando la variable se expande, en la etapa 4, su contenido es texto. echo recibe a; y ls como argumentos y los muestra.
9. ¿Por qué no funciona guardar -l "mis documentos" en una variable y pasarla como ls $opciones?
Porque las comillas que están dentro del valor son datos, no sintaxis. La división en palabras corta por los espacios y produce -l, "mis y documentos", con las comillas pegadas. La solución es usar un array.
10. ¿Qué recibe gzip en gzip *.log si no hay ningún archivo .log?
El texto literal *.log, porque un patrón sin coincidencias se deja tal cual. gzip responde que no existe un archivo con ese nombre.
11. ¿Por qué dir="~/datos"; cd "$dir" falla?
Porque la tilde solo se expande sin comillas. La variable contiene literalmente ~/datos, y cd busca un directorio llamado ~. Se corrige con dir="$HOME/datos" o con dir=~/datos.
12. ¿Qué etapas desactivan las comillas dobles, y cuáles no?
Desactivan el corte por espacios y operadores, las llaves, la tilde, la división en palabras y los comodines. Permiten las variables, la aritmética y la sustitución de comandos.
13. ¿Qué significa ambiguous redirect?
Que la palabra que sigue a un operador de redirección, después de las expansiones, dio más de un nombre (o ninguno). Ocurre típicamente con una variable sin comillas que contiene espacios. Se corrige entrecomillándola.
14. ¿Por qué if [$x -gt 0] da un error como [5: command not found?
Porque [ es un comando y necesita estar separado por espacios. Sin el espacio, [$x forma una sola palabra, que tras la expansión es [5, y Bash busca un programa con ese nombre.
15. ¿Qué muestra set -x?
Cada comando justo antes de ejecutarse, después de todas las expansiones, precedido de +. Los argumentos con espacios o caracteres especiales aparecen entre comillas simples, de modo que se ve qué recibe exactamente el programa.
16. ¿En qué lugares no hacen falta comillas alrededor de una variable?
En el lado derecho de una asignación, dentro de [[ ]] y en la palabra de un case, porque allí no se aplican la división en palabras ni los comodines. Ponerlas no hace daño.
Para practicar
- Define la función
argso guárdala como script en~/bin/args. Pruébala con todos los ejemplos del tema. - Predice, antes de ejecutarlo, cuántos argumentos recibe
args x{1,2} "$HOME" '$HOME' ~ "a b"c. Compruébalo. - Crea un directorio de pruebas con los archivos
uno.txt,dos.txtymi informe.txt. Ejecutafor f in $(ls); do args "$f"; doney luegofor f in *; do args "$f"; done. Explica la diferencia. - En ese mismo directorio, guarda
m="Precio: 2 * 3"y comparaecho $mconecho "$m". Repite en un directorio vacío. - Prueba
n=5; echo {1..$n}y luegoseq 1 "$n". - Activa
set -xy ejecuta la líneatarde la sección 12 contar -tzfen lugar de-czf, o simplemente conargsen lugar detar. Observa la traza. - Escribe un pequeño script con tres de los errores de la tabla de la sección 15 y pásalo por
shellcheck. ¿Los detecta todos?