1. Todo es texto, hasta que se calcula
Como vimos en el tema 5, una variable de Bash guarda siempre texto. Escribir una operación no la resuelve: 2+3 es una cadena de tres caracteres, y += une textos.
$ echo 2+3
2+3
$ n=5; n+=1; echo "$n"
51
Para que Bash trate un texto como número hay que pedírselo explícitamente, con un contexto aritmético. Dentro de él, los textos se interpretan como números enteros, los nombres como variables, y los símbolos como operadores. Hay dos formas de abrir ese contexto, y las dos usan doble paréntesis:
| Forma | Qué es | Produce | Se usa para |
|---|---|---|---|
$(( expresión )) | Una expansión, como $var o $( ). | El resultado, como texto. | Usar el resultado: asignarlo, mostrarlo, pasarlo a un comando. |
(( expresión )) | Un comando. | Un código de salida: 0 si el resultado no es cero. | Modificar variables y tomar decisiones con if y while. |
2. La expansión aritmética: $(( ))
$(( expresión )) calcula la expresión y se reemplaza por el resultado. Dentro de los paréntesis las variables se escriben sin $ (aunque con $ también funcionan), y los espacios son libres, a diferencia de una asignación:
$ copiados=12; omitidos=3
$ total=$(( copiados + omitidos ))
$ echo "$total"
15
$ echo "Minutos en una semana: $(( 60 * 24 * 7 ))"
Minutos en una semana: 10080
$ sleep $(( RANDOM % 30 )) # esperar entre 0 y 29 segundos
Los operadores son los de la mayoría de los lenguajes de programación, con la precedencia habitual: primero la potencia, luego la multiplicación, la división y el resto, y por último la suma y la resta. Los paréntesis cambian el orden.
| Operador | Operación | Ejemplo | Resultado |
|---|---|---|---|
+ - | Suma y resta | $(( 10 - 4 )) | 6 |
* | Multiplicación | $(( 6 * 7 )) | 42 |
/ | División entera | $(( 7 / 2 )) | 3 |
% | Resto de la división | $(( 7 % 2 )) | 1 |
** | Potencia | $(( 2 ** 10 )) | 1024 |
( ) | Agrupar | $(( (2 + 3) * 4 )) | 20 |
Dentro de $(( )) el * no se expande como comodín ni hace falta escaparlo, porque el contexto aritmético se analiza aparte. Es una de las ventajas frente al antiguo expr, como veremos en la sección 7.
3. División entera, resto y redondeo
La aritmética de Bash es entera: la división descarta la parte decimal, sin redondear. Con números negativos, descarta hacia el cero, y el resto toma el signo del dividendo:
$ echo $(( 7 / 2 )) $(( 7 % 2 ))
3 1
$ echo $(( -7 / 2 )) $(( -7 % 2 ))
-3 -1
$ echo $(( 5 / 0 ))
bash: 5 / 0 : division by 0 (error token is "0 ")
La división por cero es un error que interrumpe la línea en que ocurre. En un script, cuando el divisor viene de los datos, como el total de líneas de un archivo que podría estar vacío, conviene comprobarlo antes.
Que la división sea entera obliga a pensar el orden de las operaciones. El caso típico es el porcentaje: si se divide primero, el resultado intermedio se trunca a cero.
$ echo $(( 45 / 60 * 100 )) # 45/60 da 0, y 0 × 100 = 0
0
$ echo $(( 45 * 100 / 60 )) # multiplicar primero
75
La regla es multiplicar antes de dividir. Y para redondear en lugar de truncar, se suma la mitad del divisor antes de dividir: (a + b / 2) / b. Por ejemplo, 2 de 3 es un 66,67 %:
$ echo $(( 2 * 100 / 3 )) # truncado
66
$ echo $(( (2 * 100 + 3 / 2) / 3 )) # redondeado
67
El resto, por su parte, es más útil de lo que parece. Sirve para saber si un número es par (n % 2 da 0), para hacer algo cada tantas vueltas de un bucle (i % 100 == 0), para descomponer cantidades en unidades, como segundos en horas y minutos (sección 14), y para obtener un número al azar dentro de un rango: RANDOM % 6 + 1 simula un dado.
4. El comando (( ))
Sin el $ delante, (( expresión )) es un comando: calcula la expresión y no produce texto. Sirve para dos cosas. La primera, modificar variables con los operadores de asignación, sin repetir el nombre:
$ (( total = 10 ))
$ (( total += 5 )) # total = total + 5
$ (( total *= 2 )) # total = total * 2
$ echo "$total"
30
| Forma | Equivale a |
|---|---|
(( x += n )), (( x -= n )) | x=$(( x + n )), x=$(( x - n )) |
(( x *= n )), (( x /= n )), (( x %= n )) | Lo mismo con multiplicación, división y resto. |
(( x++ )), (( x-- )) | Sumar o restar 1, después de usar el valor. |
(( ++x )), (( --x )) | Sumar o restar 1, antes de usar el valor. |
La segunda, y la más importante, es tomar decisiones. Como todo comando, (( )) termina con un código de salida, y la regla es: si el resultado de la expresión es distinto de cero, el código es 0, es decir, éxito o «verdadero»; si el resultado es cero, el código es 1, «falso».
$ (( 5 > 3 )); echo $?
0
$ (( 0 )); echo $?
1
$ uso=93
$ (( uso >= 90 )) && echo "Disco casi lleno"
Disco casi lleno
La regla parece invertida respecto de otros lenguajes, donde 0 es falso, pero es coherente: en la expresión, 0 es falso; en el código de salida, 0 es éxito. (( )) hace la traducción. Lo retomaremos en el tema 10, porque es la base de cómo deciden if y while.
5. Incrementar, y la trampa del cero
Contar es lo más común que hace un script con números, y hay varias formas de sumar uno a un contador. Todas dejan el mismo valor en la variable, pero no el mismo código de salida:
$ n=0; (( n++ )); echo "código $?, n vale $n"
código 1, n vale 1
$ n=0; (( ++n )); echo "código $?, n vale $n"
código 0, n vale 1
n++ incrementa la variable, pero el valor de la expresión es el que tenía antes: cero. Y una expresión que vale cero da código de salida 1. En la terminal no importa. En un script con set -e, que se detiene ante cualquier comando que falle, es una trampa clásica: el primer (( contador++ )) con el contador en cero termina el script en silencio, sin ningún mensaje.
En scripts con set -e, usa contador=$(( contador + 1 )) o (( ++contador )). La primera es una asignación, que siempre termina con éxito; la segunda vale el número ya incrementado, que nunca es cero si se parte de cero. Es la forma que usaron los scripts de los temas 1 y 4. Evita (( contador++ )) y (( contador += 0 )) como instrucciones sueltas.
6. Comparaciones y decisiones
Dentro del contexto aritmético se puede comparar con los operadores habituales, que dan 1 si la comparación es cierta y 0 si no. Combinadas con (( )), sirven directamente como condiciones:
| Operador | Significado | Operador | Significado |
|---|---|---|---|
== | Igual | != | Distinto |
< | Menor | > | Mayor |
<= | Menor o igual | >= | Mayor o igual |
&& | Y lógico | || | O lógico |
! | Negación | c ? a : b | a si c es cierto; si no, b |
if (( uso >= UMBRAL )); then
echo "Disco casi lleno: $uso %"
fi
(( errores == 0 && avisos < 10 )) && echo "Todo en orden"
while (( intentos < 5 )); do # reintentar hasta cinco veces (tema 15)
…
done
Dentro de (( )), los símbolos < y > son comparaciones, no redirecciones, porque Bash analiza el interior como una expresión. Fuera, en [ ] o [[ ]], no es así: allí los números se comparan con -lt, -gt y sus parientes, y < compara textos alfabéticamente. Para comparar números, (( )) es la forma más legible, y la que usará este curso.
El operador ternario, ?:, elige entre dos valores numéricos según una condición, en una sola expresión:
$ intentos=3
$ espera=$(( intentos > 2 ? 60 : 5 )) # esperar más tras varios fallos
$ echo "$espera"
60
7. let, expr y declare -i
En scripts antiguos encontrarás otras formas de calcular. Conviene reconocerlas, aunque no usarlas:
| Forma antigua | Qué es | Por qué no usarla |
|---|---|---|
let "n = n + 1" | Un comando interno, equivalente a (( )). | Necesita comillas para los espacios y los *; (( )) hace lo mismo sin ellas. |
n=`expr $n + 1` | Un programa externo, de la época anterior a la aritmética de la shell. | Crea un proceso por operación; el * hay que escaparlo (expr 5 \* 2), y cada operador debe ir separado por espacios. |
declare -i n; n=n+1 | Una variable con atributo entero: toda asignación se calcula. | El cálculo ocurre sin que nada en la línea lo indique, y += cambia de significado, como vimos en el tema 5. |
La regla del curso es simple: $(( )) cuando se necesita el resultado, y (( )) para modificar variables y para condiciones.
8. Los límites de los enteros
Bash calcula con enteros de 64 bits con signo. El mayor número representable es 9 223 372 036 854 775 807, algo más de nueve trillones, y el menor, su negativo menos uno. Es suficiente para casi todo, incluidos tamaños de archivo en bytes y marcas de tiempo en milisegundos. Pero si un cálculo se pasa de ese límite, el resultado da la vuelta sin ningún aviso:
$ echo $(( 2**63 - 1 ))
9223372036854775807
$ echo $(( 9223372036854775807 + 1 )) # desbordamiento: pasa al extremo negativo
-9223372036854775808
$ echo $(( 2**64 ))
0
En la práctica, el riesgo aparece al multiplicar para preservar decimales, como en la sección 3. Un tamaño de 10 terabytes en bytes, multiplicado por 1000, todavía cabe; multiplicado por un millón, ya no. Si un cálculo maneja números muy grandes, conviene pensar el orden de las operaciones o pasar a bc, que no tiene límite de tamaño.
9. Ceros a la izquierda y bases
En el contexto aritmético, un número que empieza con 0 se interpreta en octal, base 8, y uno que empieza con 0x, en hexadecimal. Es una herencia del lenguaje C, y es la causa de uno de los errores más desconcertantes de Bash:
$ echo $(( 07 + 1 ))
8
$ echo $(( 010 + 1 )) # 010 en octal es 8
9
$ echo $(( 08 + 1 )) # 8 no es un dígito octal
bash: 08: value too great for base (error token is "08")
El problema real aparece con fechas y horas, que date y otros programas escriben con ceros a la izquierda. Un script que calcula con el mes o la hora funciona perfectamente de enero a julio, y falla en agosto y septiembre, o a las 8 y a las 9 de la mañana:
hora="$(date +%H)" # "08" a las ocho de la mañana
siguiente=$(( hora + 1 )) # error: 08 no es octal válido
La solución es indicar la base explícitamente con el prefijo 10#, que obliga a leer el número en decimal. Funciona también con variables: $(( 10#$hora + 1 )). Otra alternativa es pedirle a date el número sin ceros: date +%-H en GNU.
El mismo prefijo sirve para cualquier base entre 2 y 64, lo que permite convertir números entre sistemas. Para la conversión inversa, de decimal a otra base, printf tiene formatos para octal y hexadecimal:
$ echo $(( 10#08 )) $(( 16#ff )) $(( 0x1f )) $(( 2#1010 ))
8 255 31 10
$ printf '%o %x %X\n' 493 255 255 # octal, hexadecimal
755 ff FF
El octal tiene un uso cotidiano en Linux: los permisos. 755 es un número octal, y printf '%o' 493 muestra que 493 en decimal es exactamente ese permiso.
10. Validar antes de calcular
El contexto aritmético es muy tolerante, y eso es peligroso cuando los datos vienen de afuera. Un texto que no es un número no siempre produce un error: si es una palabra, Bash la toma como nombre de variable; si esa variable no existe, vale cero.
$ x=abc; echo $(( x + 1 )) # «abc» es una variable inexistente: vale 0
1
$ x="3 + 4"; echo $(( x * 2 )) # el valor se evalúa como expresión
14
$ x=12abc; echo $(( x + 1 ))
bash: 12abc: value too great for base (error token is "12abc")
Los dos primeros casos fallan en silencio, con un resultado incorrecto. Y hay un problema más grave: como el valor se evalúa como expresión, un texto especialmente preparado puede hacer que Bash ejecute comandos al calcularlo. Por eso, todo número que llega como argumento, desde un archivo o desde el teclado debe validarse antes de usarse en un cálculo. La forma más clara es con una expresión regular, que veremos en el tema 28; por ahora, basta con la receta:
dias="${1:-30}"
if [[ ! "$dias" =~ ^[0-9]+$ ]]; then
echo "Error: los días deben ser un número entero, no «$dias»" >&2
exit 2
fi
dias=$(( 10#$dias )) # quitar ceros a la izquierda: 007 → 7
La última línea completa la validación: un número como 007 pasa la expresión regular, pero se leería en octal. Con 10#, se normaliza a decimal una sola vez, y el resto del script ya puede usarlo sin precauciones.
11. Evitar los decimales
Antes de recurrir a otra herramienta para calcular con decimales, conviene preguntarse si hacen falta. Muchas veces se pueden evitar eligiendo una unidad más pequeña, en la que todas las cantidades son enteras: centavos en lugar de pesos, milisegundos en lugar de segundos, bytes en lugar de megabytes. Se calcula con enteros, y solo al mostrar el resultado se lo divide para presentarlo:
$ precio=12550; cantidad=3 # $125,50
$ total=$(( precio * cantidad ))
$ printf 'Total: $%d,%02d\n' $(( total / 100 )) $(( total % 100 ))
Total: $376,50
La división entera da la parte entera, el resto da los centavos, y %02d los completa con un cero a la izquierda cuando son menos de diez. El mismo truco sirve para mostrar un porcentaje con un decimal: se calcula «por mil» en lugar de «por cien», y se separan las unidades de las décimas.
$ por_mil=$(( (2 * 1000 + 3 / 2) / 3 )) # 667, redondeado
$ printf '%d,%d %%\n' $(( por_mil / 10 )) $(( por_mil % 10 ))
66,7 %
12. Decimales con bc
Cuando los decimales son inevitables, como en un promedio, una tasa o una conversión de unidades, Bash recurre a un programa externo. El clásico es bc, una calculadora de precisión arbitraria que lee expresiones desde su entrada. No siempre viene instalado; en Debian y Ubuntu, sudo apt install bc.
$ echo "10 / 3" | bc # por defecto, sin decimales
3
$ echo "scale=2; 10 / 3" | bc # scale: cantidad de decimales
3.33
$ echo "10 / 3" | bc -l # -l: biblioteca matemática, 20 decimales
3.33333333333333333333
$ promedio=$(echo "scale=2; 1873 / 26" | bc)
$ echo "$promedio"
72.03
scale indica cuántos decimales conservar, y bc trunca, no redondea. Para comparar números con decimales, que (( )) no admite, se le pide a bc la comparación: responde 1 si es cierta y 0 si no, y ese resultado sí se puede usar en (( )).
carga="$(cut -d' ' -f1 /proc/loadavg)" # por ejemplo, 2.37
if (( $(echo "$carga > 2.0" | bc) )); then
echo "Carga alta: $carga"
fi
13. Decimales con awk
awk, que conociste en el curso de Terminal, calcula con decimales de forma nativa y está instalado en todos los sistemas. Para un cálculo suelto, se usa con un bloque BEGIN, que se ejecuta sin leer ninguna entrada, y los valores se pasan con -v:
$ awk -v a=1873 -v b=26 'BEGIN { printf "%.2f\n", a / b }'
72.04
A diferencia de bc, el printf de awk redondea: 72,038… se muestra como 72.04. Pero el gran terreno de awk no son los cálculos sueltos, sino los que recorren un archivo. Sumar o promediar una columna, que en Bash requeriría un bucle, en awk es una línea:
$ awk '{ suma += $1; n++ } END { printf "%d mediciones, promedio %.1f ms\n", n, suma / n }' tiempos.txt
26 mediciones, promedio 72.0 ms
| Necesitas | Usa |
|---|---|
| Contar, sumar enteros, comparar, porcentajes aproximados | $(( )) y (( )): sin procesos, lo más rápido. |
| Un resultado con decimales para mostrar | Enteros en una unidad menor, o awk con printf. |
| Comparar números con decimales | bc o awk. |
| Precisión arbitraria o números enormes | bc. |
| Cálculos sobre las columnas de un archivo | awk, siempre. |
El printf de Bash también da formato a decimales (printf '%.2f' 3.14159), pero respeta la configuración regional, y en español el separador decimal es la coma. Con un idioma como es_AR.UTF-8, printf '%.2f\n' 3.14159 responde invalid number y muestra 3,00, porque espera 3,14159. Como bc y awk producen siempre el punto, conviene dar formato dentro de awk, o ejecutar printf con LC_NUMERIC=C.
14. Calcular con fechas y tiempos
Las fechas no son números, pero se convierten en uno: la cantidad de segundos transcurridos desde el 1 de enero de 1970, llamada tiempo Unix o epoch. date +%s da ese número para el momento actual, y date -d para cualquier fecha. A partir de ahí, las diferencias entre fechas son restas:
$ date +%s
1792000000
$ ahora=$(date +%s); fin=$(date -d 2026-12-31 +%s)
$ echo "Faltan $(( (fin - ahora) / 86400 )) días para fin de año"
Faltan 77 días para fin de año
86 400 son los segundos de un día. Para medir cuánto tarda una tarea dentro de un script, la variable SECONDS del tema 5 es la más simple. Y para presentar una duración en horas, minutos y segundos, se combinan la división y el resto:
inicio=$SECONDS
tar -czf respaldo.tgz ~/proyecto
duracion=$(( SECONDS - inicio )) # por ejemplo, 3725 segundos
printf 'Duración: %02d:%02d:%02d\n' \
$(( duracion / 3600 )) $(( duracion % 3600 / 60 )) $(( duracion % 60 ))
# Duración: 01:02:05
duracion / 3600 da las horas completas; duracion % 3600 los segundos que sobran de ellas, y dividido por 60, los minutos; duracion % 60, los segundos restantes. Es la misma descomposición que se usa para pasar bytes a kilobytes y megabytes, o centavos a pesos.
15. Un script completo
Este script muestra cuánto ocupa un directorio y qué porcentaje del disco representa, con un decimal y sin salir de la aritmética entera. Reúne la multiplicación antes de la división, el redondeo y la presentación con printf:
#!/usr/bin/env bash
#
# ocupacion — cuánto ocupa un directorio y qué parte del disco representa.
#
# Uso: ocupacion [DIRECTORIO]
#
set -euo pipefail
export LC_ALL=C # salida de du y df sin variaciones regionales
dir="${1:-.}"
bytes=$(du -sb -- "$dir" | cut -f1) # tamaño del directorio
total=$(df -B1 --output=size -- "$dir" | tail -1) # tamaño del disco
# Megabytes, redondeados: se suma medio MiB antes de dividir.
mib=$(( (bytes + 524288) / 1048576 ))
# Porcentaje con un decimal: se calcula por mil y se separa la última cifra.
por_mil=$(( (bytes * 1000 + total / 2) / total ))
printf '%s ocupa %d MiB: el %d.%d %% del disco\n' \
"$dir" "$mib" $(( por_mil / 10 )) $(( por_mil % 10 ))
$ ocupacion ~/videos
/home/ana/videos ocupa 1229 MiB: el 3.0 % del disco
$ ocupacion ~/proyecto
/home/ana/proyecto ocupa 48 MiB: el 0.1 % del disco
du -sbydf -B1piden los tamaños en bytes, para no tener que convertir unidades distintas.cut -f1ytail -1quitan el nombre del directorio y la línea de encabezado.- Multiplicar por 1000 antes de dividir conserva un decimal. Con un disco de un terabyte,
bytes * 1000es del orden de 1015, muy por debajo del límite de 64 bits. - Sumar la mitad del divisor antes de dividir redondea en lugar de truncar, en los dos cálculos.
- El punto decimal se escribe en el formato de
printf, entre los dos%d, de modo que no depende de la configuración regional. Y%%muestra el signo de porcentaje.
16. Errores frecuentes
| Escribiste | Qué pasa | Corrección |
|---|---|---|
n+=1 | Une texto: 5 pasa a 51. | (( n += 1 )) o n=$(( n + 1 )) |
(( n++ )) con set -e | Si n era 0, el script termina en silencio. | n=$(( n + 1 )) o (( ++n )) |
$(( a / b * 100 )) | Si a < b, da 0. | $(( a * 100 / b )) |
$(( hora + 1 )) con hora=08 | value too great for base | $(( 10#$hora + 1 )) |
$(( 1.5 * 2 )) | syntax error: invalid arithmetic operator | bc, awk, o enteros en otra unidad. |
$(( total / cantidad )) con cantidad 0 | division by 0 | Comprobar antes: (( cantidad > 0 )). |
$(( x + 1 )) con x sin validar | Resultados silenciosamente incorrectos, o ejecución de código. | Validar con =~ ^[0-9]+$. |
[ $a > $b ] | Crea un archivo llamado como $b: > es una redirección. | (( a > b )) |
printf '%.2f' "$x" en español | invalid number si x usa punto decimal. | LC_NUMERIC=C printf …, o awk. |
17. Resumen
- Bash calcula solo dentro de un contexto aritmético:
$(( ))produce el resultado y(( ))es un comando que modifica variables o decide. - Dentro de los dobles paréntesis, las variables van sin
$, los espacios son libres y*no es un comodín. - La aritmética es entera:
/descarta los decimales y%da el resto. Se multiplica antes de dividir, y se suma la mitad del divisor para redondear. (( expresión ))termina con éxito si el resultado no es cero. Sirve directamente como condición enif,while,&&y||.(( n++ ))connen cero da código 1, y detiene un script conset -e. Se cuenta conn=$(( n + 1 ))o(( ++n )).- Los números se comparan con
==,<,>=y demás dentro de(( ));?:elige entre dos valores. let,exprydeclare -ison formas antiguas; se prefieren los dobles paréntesis.- Los enteros son de 64 bits con signo, y al desbordarse dan la vuelta sin aviso.
- Un cero a la izquierda indica octal:
08y09dan error.10#fuerza la base decimal. - Los números que vienen de afuera se validan antes de calcular, porque un texto cualquiera puede dar resultados silenciosamente erróneos.
- Muchos decimales se evitan calculando en una unidad menor. Si no,
bcpara precisión y comparaciones, yawkpara dar formato y para columnas de archivos. date +%sconvierte fechas en segundos, y la división y el resto descomponen duraciones en horas, minutos y segundos.
18. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Qué diferencia hay entre $(( a + b )) y (( a + b ))?
La primera es una expansión: se reemplaza por el resultado, que se puede asignar o mostrar. La segunda es un comando: no produce texto, y termina con código 0 si el resultado es distinto de cero y con 1 si es cero.
2. ¿Cuánto valen $(( 17 / 5 )) y $(( 17 % 5 ))?
3 y 2. La división es entera y descarta los decimales; el resto es lo que sobra: 17 = 3 × 5 + 2.
3. ¿Por qué $(( 30 / 40 * 100 )) da 0, y cómo se corrige?
Porque 30 / 40 es 0 en división entera, y 0 × 100 es 0. Se corrige multiplicando primero: $(( 30 * 100 / 40 )), que da 75.
4. ¿Cómo se calcula a / b redondeado en lugar de truncado?
Sumando la mitad del divisor antes de dividir: $(( (a + b / 2) / b )).
5. ¿Por qué (( n++ )) puede detener un script con set -e?
Porque el valor de n++ es el que n tenía antes de incrementarse. Si era 0, la expresión vale 0, y (( )) termina con código 1, que set -e trata como un fallo.
6. ¿Qué código de salida da (( 3 > 5 ))?
1, porque la comparación es falsa y vale 0, y una expresión que vale 0 da código de salida 1.
7. ¿Qué hace pausa=$(( fallos > 3 ? 300 : 10 ))?
Asigna 300 a pausa si fallos es mayor que 3, y 10 en caso contrario.
8. ¿Por qué no conviene usar expr en scripts nuevos?
Porque es un programa externo, que crea un proceso por operación, y exige escapar el * y separar cada operador con espacios. $(( )) hace lo mismo dentro de Bash, con una sintaxis más natural.
9. ¿Qué ocurre si un cálculo supera 9 223 372 036 854 775 807?
Se desborda: el resultado da la vuelta hacia los números negativos, sin ningún mensaje de error.
10. Un script falla con value too great for base solo a las 8 y a las 9 de la mañana. ¿Por qué?
Porque calcula con la hora que da date +%H, que a esas horas es 08 o 09. El cero inicial hace que Bash lo lea como octal, donde 8 y 9 no son dígitos válidos. Se corrige con 10#$hora.
11. Con x=hola, ¿qué da $(( x + 1 )), y por qué es un problema?
Da 1, porque hola se interpreta como el nombre de una variable, que no existe y vale 0. El problema es que no hay ningún error: el resultado es incorrecto en silencio. Por eso los números que vienen de afuera deben validarse.
12. ¿Cómo se muestra un total de 12 345 centavos como $123,45 sin usar decimales?
Con printf '$%d,%02d\n' $(( t / 100 )) $(( t % 100 )): la división da los pesos, el resto los centavos, y %02d agrega un cero si son menos de diez.
13. ¿Qué muestra echo "scale=3; 2 / 3" | bc?
.666. scale fija tres decimales, y bc trunca en lugar de redondear. (bc omite el cero antes del punto.)
14. ¿Por qué printf '%.2f\n' 3.14159 puede fallar en un sistema en español?
Porque printf respeta la configuración regional, y en español el separador decimal es la coma. Espera 3,14159, y con un punto responde invalid number. Se evita con LC_NUMERIC=C o dando formato con awk.
15. ¿Cómo se calcula la cantidad de días entre hoy y una fecha?
Convirtiendo las dos fechas a segundos con date +%s y date -d FECHA +%s, restándolas y dividiendo por 86 400, la cantidad de segundos de un día.
Para practicar
- Calcula con
$(( ))cuántos segundos tiene un año de 365 días, y cuántos días son mil millones de segundos. - Escribe un script que reciba dos números y muestre su suma, su producto, el cociente entero, el resto y el porcentaje que el primero representa del segundo, redondeado. Valida que los dos sean enteros.
- Comprueba en tu terminal la diferencia de código de salida entre
(( n++ ))y(( ++n ))partiendo den=0. Luego escribe un script conset -eque cuente con(( n++ ))y observa qué pasa. - Prueba
h=09; echo $(( h + 1 ))y corrígelo con10#. - Muestra el porcentaje de 7 sobre 9 con dos decimales, de tres formas: con enteros «por diez mil», con
bcy conawk. - Crea un archivo con diez números, uno por línea, y calcula con
awksu suma, su promedio y el mayor. - Agrega al script
ocupacionla cantidad de archivos del directorio, contada confind "$dir" -type f | wc -l, y el tamaño medio por archivo en KiB. - Escribe una línea que muestre cuántos días faltan para tu próximo cumpleaños.