1. Tres formas de recibir datos
Un script puede obtener los datos que necesita de tres maneras, y elegir bien entre ellas es parte del diseño:
| Forma | Ejemplo | Ventajas | Limitaciones |
|---|---|---|---|
| Argumentos | respaldo ~/docs | Explícitos, fáciles de repetir y de usar desde otros scripts y desde cron. | Hay que conocerlos de antemano. |
| Variables de entorno | DIAS=7 respaldo | Configuración opcional sin complicar la línea de comandos (tema 5). | Poco visibles: hay que documentarlas. |
| Preguntar | ¿Nombre del proyecto? | Guía a quien no conoce el script; permite datos secretos y confirmaciones. | Necesita a alguien delante. Bloquea un script que corre solo. |
La regla práctica: un script de automatización debe poder ejecutarse sin preguntar nada, porque lo va a ejecutar cron o otro script. Preguntar es un complemento para el uso a mano: completar lo que falta, confirmar algo peligroso, pedir un secreto. En la sección 15 veremos cómo combinar las tres fuentes en ese orden de prioridad.
2. El comando read
read lee una línea de su entrada estándar, que normalmente es el teclado, y la guarda en una o más variables. Se detiene hasta que se pulsa Enter. Con -p muestra antes un texto, el indicador:
$ read -rp "¿Cómo te llamas? " nombre
¿Cómo te llamas? Ana María
$ echo "Hola, $nombre"
Hola, Ana María
El indicador de -p se muestra en la salida de errores, no en la estándar, de modo que no se mezcla con los datos si la salida del script se redirige. Y solo aparece cuando la entrada viene de una terminal. Si no se indica ninguna variable, la línea queda en la variable REPLY, aunque por claridad conviene nombrarla siempre.
| Opción | Efecto | Sección |
|---|---|---|
-r | No interpreta las barras invertidas. Va siempre. | 3 |
-p texto | Muestra un indicador. | 2 |
-a nombre | Guarda las palabras en un array. | 7 |
-e, -i texto | Permite editar la línea, con un valor inicial. | 9 |
-s | No muestra lo que se escribe. | 11 |
-t segundos | Tiempo límite para responder. | 12 |
-n N | Lee N caracteres, sin esperar Enter. | 13 |
-d carácter | Lee hasta ese carácter en lugar del salto de línea. | Temas 8 y 16 |
3. Siempre con -r
Sin opciones, read trata la barra invertida como carácter de escape: la elimina y conserva el carácter siguiente. Es un comportamiento heredado que casi nunca se quiere, y que altera rutas de Windows, expresiones regulares o cualquier texto con barras:
$ read ruta
C:\temp\nuevo
$ echo "$ruta"
C:tempnuevo
$ read -r ruta
C:\temp\nuevo
$ echo "$ruta"
C:\temp\nuevo
La opción -r (de raw, «en crudo») desactiva ese tratamiento. La regla es usarla siempre; ShellCheck avisa de cada read sin ella con el código SC2162. En los ejemplos de este curso aparece en todos.
4. Cómo se reparten las palabras
Si se le dan varias variables, read divide la línea en palabras, igual que la división en palabras del tema 3, y asigna una a cada variable. La regla clave es qué pasa cuando no coinciden las cantidades: la última variable recibe todo lo que sobra, y si faltan palabras, las variables sobrantes quedan vacías.
$ read -r nombre apellido <<< "Ana María Pérez"
$ echo "[$nombre] [$apellido]"
[Ana] [María Pérez]
$ read -r a b c <<< "uno"
$ echo "[$a] [$b] [$c]"
[uno] [] []
El símbolo <<< que aparece aquí es un here-string: le pasa a un comando un texto como si fuera su entrada estándar. Es la forma más cómoda de aplicar read a una variable, y lo usaremos en el resto del tema para mostrar los ejemplos sin tener que escribir en el teclado.
El comportamiento de la última variable es útil: permite separar la primera palabra del resto. Por ejemplo, para leer un comando y sus argumentos:
$ read -r accion resto <<< "copiar informe final.pdf /respaldos"
$ echo "acción: $accion | resto: $resto"
acción: copiar | resto: informe final.pdf /respaldos
5. Conservar la línea intacta
Al dividir en palabras, read también elimina los espacios del principio y del final de la línea. Con una sola variable, eso significa que no se recibe la línea exactamente como estaba:
$ read -r x <<< " hola mundo "
$ echo "[$x]"
[hola mundo]
$ IFS= read -r x <<< " hola mundo "
$ echo "[$x]"
[ hola mundo ]
Los espacios interiores se conservan en los dos casos, porque solo hay una variable. Lo que cambia son los de los extremos. La forma IFS= read -r, con IFS vacío solo para ese comando, desactiva la división por completo y recibe la línea tal cual. Es la forma estándar de leer líneas de un archivo cuando importa su contenido exacto, como un archivo de configuración o un código con sangría, y la volveremos a ver en el tema 16.
6. IFS: separar campos
La variable IFS (Internal Field Separator) contiene los caracteres por los que se divide en palabras: por defecto, el espacio, el tabulador y el salto de línea. Cambiándola, read separa por cualquier otro carácter, y se convierte en un analizador de campos:
$ linea="ana:x:1000:1000:Ana Pérez:/home/ana:/bin/bash"
$ IFS=: read -r usuario _ uid gid nombre casa shell <<< "$linea"
$ echo "$usuario ($nombre) usa $shell"
ana (Ana Pérez) usa /bin/bash
Tres detalles de esta línea son importantes:
IFS=:delante dereadcambiaIFSsolo para ese comando, como cualquier asignación seguida de un comando (tema 5). El resto del script conserva el valor normal. CambiarIFSde forma global es una fuente de errores difíciles de rastrear.- El espacio de
Ana Pérezno corta, porque ahora solo se separa por los dos puntos. - La variable
_es una convención para descartar un campo que no interesa, aquí laxde la contraseña.
Hay una diferencia sutil entre separar por espacios y por otro carácter. Los espacios, tabuladores y saltos de línea de IFS se agrupan: varios seguidos cuentan como un solo separador. Cualquier otro carácter, no: dos separadores seguidos delimitan un campo vacío. Es exactamente lo que se necesita para los archivos con campos separados por comas, donde un campo puede faltar:
$ IFS=, read -r a b c <<< "rojo,,azul"
$ echo "[$a] [$b] [$c]"
[rojo] [] [azul]
$ IFS=" " read -r a b c <<< "rojo azul"
$ echo "[$a] [$b] [$c]"
[rojo] [azul] []
Esta técnica alcanza para formatos simples, como /etc/passwd o un CSV sin comillas. Un CSV real, con campos entre comillas que pueden contener comas, requiere otra herramienta; lo discutiremos en el tema 30.
7. Leer en un array: read -a
Cuando la cantidad de campos no se conoce de antemano, la opción -a guarda todas las palabras en un array, una por elemento. Combinada con IFS, separa un texto por cualquier carácter:
$ read -ra palabras <<< "uno dos tres"
$ declare -p palabras
declare -a palabras=([0]="uno" [1]="dos" [2]="tres")
$ IFS=: read -ra dirs <<< "$PATH"
$ echo "El PATH tiene ${#dirs[@]} directorios; el primero es ${dirs[0]}"
El PATH tiene 8 directorios; el primero es /home/ana/bin
Es la forma de separar en campos que recomendamos en el tema 8, en lugar de array=($texto), que además de dividir expandiría comodines.
8. De dónde lee read
read lee de su entrada estándar, sea cual sea. Con una redirección, lee de un archivo; pero lee una sola línea, la primera. Para leer todas hace falta un bucle, que veremos en el tema 16, o mapfile.
$ read -r primera < /etc/hostname # la primera línea de un archivo
$ read -r carga _ < /proc/loadavg # el primer campo de la primera línea
$ echo "$primera, carga $carga"
equipo, carga 0.42
La segunda línea es un pequeño truco que vale la pena retener: leer el primer campo de un archivo con read, sin crear ningún proceso, en lugar de $(cut -d' ' -f1 /proc/loadavg).
Lo que no funciona es leer desde una tubería, por la misma razón que vimos con mapfile: cada parte de una tubería corre en un proceso aparte, y la variable se asigna en ese proceso, que desaparece al terminar.
$ echo "hola" | read -r saludo
$ echo "[$saludo]"
[]
$ read -r saludo <<< "$(echo hola)" # correcto: here-string
$ read -r saludo < <(echo hola) # correcto: sustitución de procesos
Por último, conviene saber qué devuelve read. Termina con código 0 si leyó una línea completa, y con 1 si llegó al final de la entrada sin encontrar un salto de línea. Ese código es lo que permite usarlo como condición de un bucle, y también lo que hace que una última línea sin salto final necesite un cuidado especial, como veremos en el tema 16.
9. Valores por defecto y edición
Una pregunta con una respuesta habitual debería permitir aceptarla pulsando Enter. Hay dos formas de ofrecerlo. La más simple es mostrar el valor entre corchetes y aplicar un valor por defecto del tema 6 si la respuesta llega vacía:
read -rp "Directorio de destino [/respaldos]: " destino
destino="${destino:-/respaldos}"
La segunda usa la opción -e, que activa la edición de línea de Bash (flechas, Inicio, Fin, completado de rutas con Tab), junto con -i, que escribe un texto inicial que el usuario puede aceptar o modificar:
$ read -erp "Directorio de destino: " -i "/respaldos/$(date +%F)" destino
Directorio de destino: /respaldos/2026-10-14▌
El cursor queda al final del valor propuesto, listo para editarlo. Con -e, además, el usuario puede completar rutas con Tab, lo que es muy cómodo cuando se pide un archivo o un directorio. La opción -i solo tiene efecto junto con -e.
10. Pedir confirmación
Antes de una acción irreversible, como borrar o sobrescribir, un script usado a mano debería pedir confirmación. La convención de Unix es mostrar las opciones con la predeterminada en mayúscula: [s/N] significa que, si se pulsa Enter, la respuesta es «no».
confirmar() {
local respuesta
read -rp "$1 [s/N] " respuesta
[[ "${respuesta,,}" == s* ]] # éxito solo si empieza con s o S
}
if confirmar "¿Borrar los 128 registros anteriores a junio?"; then
find "$dir" -name '*.log' -mtime +120 -delete
else
echo "No se borró nada."
fi
La función devuelve el código de salida de su última línea, la comparación, de modo que puede usarse directamente en un if. Las funciones son el tema del bloque 5; aquí basta con ver que encapsulan la pregunta para reutilizarla. Pasar la respuesta a minúsculas con ${respuesta,,} y comparar con el patrón s* acepta s, S, si y Sí.
Para acciones destructivas, la respuesta por defecto es siempre «no»: un Enter pulsado por costumbre no debe borrar nada. Para acciones inofensivas, como continuar con un proceso, el predeterminado puede ser «sí», y se indica [S/n]. Y un script que pueda ejecutarse sin nadie delante debe ofrecer una opción para saltar la confirmación, a menudo -y o --yes, en lugar de quedar bloqueado esperando.
11. Entrada oculta: contraseñas
La opción -s (de silent) hace que lo que se escribe no aparezca en pantalla. Como tampoco se ve el Enter final, conviene escribir un salto de línea después, para que el siguiente mensaje no quede pegado al indicador:
read -rsp "Contraseña de la base de datos: " clave
echo # salto de línea tras la entrada oculta
[[ -n "$clave" ]] || { echo "La contraseña no puede estar vacía." >&2; exit 1; }
Pedir la contraseña con read -s es mucho mejor que recibirla como argumento, porque los argumentos de un proceso son visibles para otros usuarios del sistema con ps y quedan en el historial de la shell. Pero una vez en la variable, el secreto sigue requiriendo cuidado:
- No lo muestres, ni en mensajes ni en registros. Cuidado con
set -x, que mostraría la línea donde se usa. - No lo pases como argumento a otro comando, por la misma razón de
ps. Muchos programas aceptan la contraseña por una variable de entorno o por su entrada estándar:printf '%s' "$clave" | comando --password-stdin. - No lo exportes más allá del comando que lo necesita:
PGPASSWORD="$clave" psql …lo define solo para ese comando. - Bórralo al terminar de usarlo con
unset clave, si el script sigue haciendo otras cosas.
12. Tiempo límite
Con -t segundos, read espera una respuesta solo durante ese tiempo. Si se agota, termina con un código de salida mayor que 128, y la variable queda vacía. Sirve para preguntas con un valor por defecto razonable, que no deben bloquear el script indefinidamente:
if read -rt 10 -p "Se reiniciará el servicio en 10 segundos. ¿Cancelar? [c] " r; then
[[ "${r,,}" == c* ]] && { echo "Cancelado."; exit 0; }
else
echo # tiempo agotado: seguir adelante
fi
systemctl restart app
$ read -rt 3 respuesta; echo "código: $?" # sin escribir nada durante 3 segundos
código: 142
El código 142 es 128 más el número de la señal de alarma que usa read para medir el tiempo. Lo que importa en un script es distinguir el éxito (0) del tiempo agotado (mayor que 128) y del final de la entrada (1).
13. Leer una sola tecla
Con -n 1, read vuelve en cuanto se pulsa una tecla, sin esperar el Enter. Es la forma de los clásicos «pulsa una tecla para continuar» y de las preguntas de una letra:
read -rsn1 -p "Pulsa una tecla para continuar..."
echo
read -rn1 -p "¿Sobrescribir informe.pdf? [s/N] " r
echo
[[ "${r,,}" == s ]] || exit 0
En la primera línea no se indica variable, porque la tecla no importa; con -s no se muestra. La comodidad de no pulsar Enter tiene un costo: una tecla pulsada por error se toma como respuesta, sin posibilidad de corregirla. Para acciones importantes, la confirmación con Enter de la sección 10 es más segura.
14. Validar la respuesta
Lo que escribe una persona puede ser cualquier cosa: un número con letras, una ruta que no existe, nada. Un script que pregunta debe comprobar la respuesta y, si no sirve, volver a preguntar. La estructura es un bucle que se repite hasta recibir algo válido; el bucle while se estudia en el tema 15, pero su lectura es directa:
while true; do
read -rp "¿Cuántos días conservar? [30] " dias
dias="${dias:-30}"
if [[ "$dias" =~ ^[0-9]+$ ]] && (( 10#$dias >= 1 && 10#$dias <= 365 )); then
break # válido: salir del bucle
fi
echo "Escribe un número entre 1 y 365." >&2
done
¿Cuántos días conservar? [30] treinta
Escribe un número entre 1 y 365.
¿Cuántos días conservar? [30] 0
Escribe un número entre 1 y 365.
¿Cuántos días conservar? [30] 45
La validación combina dos comprobaciones que ya conoces: la expresión regular del tema 7, que asegura que solo haya dígitos, y la comparación aritmética con 10#, para que un 08 no se lea en octal. El mensaje de error dice qué se espera, no solo que algo está mal.
15. ¿Hay alguien delante?
Un script que pregunta y se ejecuta desde cron tiene un problema: no hay teclado. Su entrada estándar no es una terminal, read encuentra el final de la entrada y devuelve una respuesta vacía, o el script queda esperando algo que nunca llegará. La prueba [[ -t 0 ]] resuelve la duda: es verdadera si la entrada estándar (el descriptor 0) está conectada a una terminal.
$ [[ -t 0 ]] && echo "terminal" || echo "sin terminal"
terminal
$ bash -c '[[ -t 0 ]] && echo "terminal" || echo "sin terminal"' < /dev/null
sin terminal
Con esa prueba, un script puede seguir una estrategia en capas, que conviene adoptar como norma:
- Si el dato vino como argumento, usarlo. Es lo más explícito. argumento
- Si no, si está en una variable de entorno, usarla. entorno
- Si no, y hay una terminal, preguntar. pregunta
- Si no hay terminal, usar un valor por defecto, o terminar con un error claro que diga qué falta. Nunca quedarse esperando. error
A veces la entrada estándar de un script está ocupada con datos, por ejemplo cuando se le pasa un archivo con <, pero igual hay una persona delante a quien preguntar. En ese caso se lee directamente de la terminal con read -rp "¿Seguro? " r < /dev/tty. El archivo especial /dev/tty representa la terminal del proceso, sea cual sea su entrada estándar.
16. Un script completo
Este script crea el esqueleto de un proyecto nuevo: un directorio con un README.md y un .gitignore. Aplica la estrategia de la sección anterior: el nombre puede venir como argumento o se pregunta; la descripción y el autor pueden venir del entorno o se ofrecen para editar; y sin terminal, el script funciona sin preguntar nada, o falla con un mensaje claro si falta el nombre.
#!/usr/bin/env bash
#
# nuevo-proyecto — crea el esqueleto de un proyecto: directorio, README y .gitignore.
#
# Uso: nuevo-proyecto [NOMBRE]
# Entorno: DESCRIPCION, AUTOR valores para el README
# Si falta el nombre y hay una terminal, lo pregunta; si no hay terminal, falla.
#
set -euo pipefail
error() {
printf '%s: error: %s\n' "${0##*/}" "$*" >&2
exit 1
}
nombre="${1:-}"
if [[ -z "$nombre" ]]; then
[[ -t 0 ]] || error "falta el nombre del proyecto"
read -rp "Nombre del proyecto: " nombre
fi
[[ "$nombre" =~ ^[a-z0-9][a-z0-9-]*$ ]] || error "nombre no válido: «$nombre»"
[[ ! -e "$nombre" ]] || error "ya existe «$nombre»"
descripcion="${DESCRIPCION:-Proyecto $nombre}"
autor="${AUTOR:-$USER}"
if [[ -t 0 ]]; then
read -erp "Descripción: " -i "$descripcion" descripcion
read -erp "Autor: " -i "$autor" autor
read -rp "¿Crear «$nombre» en $PWD? [S/n] " respuesta
if [[ "${respuesta,,}" == n* ]]; then
echo "Cancelado."
exit 0
fi
fi
mkdir -- "$nombre"
printf '# %s\n\n%s\n\nAutor: %s\n' "$nombre" "$descripcion" "$autor" > "$nombre/README.md"
printf '%s\n' '*.log' '*.tmp' '.env' > "$nombre/.gitignore"
echo "Creado $nombre/"
$ nuevo-proyecto
Nombre del proyecto: Mi Proyecto
nuevo-proyecto: error: nombre no válido: «Mi Proyecto»
$ nuevo-proyecto respaldos
Descripción: Herramientas de respaldo
Autor: ana
¿Crear «respaldos» en /home/ana/proyectos? [S/n]
Creado respaldos/
$ nuevo-proyecto < /dev/null
nuevo-proyecto: error: falta el nombre del proyecto
$ DESCRIPCION="Panel de control" nuevo-proyecto panel < /dev/null
Creado panel/
$ cat panel/README.md
# panel
Panel de control
Autor: ana
- La validación ocurre una sola vez, después de obtener el nombre, venga de donde venga. Así no se repite para el argumento y para la pregunta.
- La expresión regular
^[a-z0-9][a-z0-9-]*$exige minúsculas, dígitos y guiones, y que no empiece con guion, para que el nombre no se confunda con una opción. - La confirmación es
[S/n], porque crear un directorio nuevo no destruye nada. Y antes de crearlo se comprueba que no exista, para no mezclar archivos con un proyecto anterior. - Sin terminal, el script no pregunta nada, y toma la descripción y el autor del entorno o de los valores por defecto. Puede llamarse desde otro script sin quedar bloqueado.
17. Resumen
- Un script de automatización debe poder funcionar sin preguntar. Preguntar complementa a los argumentos y al entorno para el uso manual.
read -rp "texto" varmuestra un indicador y lee una línea.-rva siempre, para no alterar las barras invertidas.- Con varias variables,
readdivide en palabras; la última recibe todo lo que sobra, y las que faltan quedan vacías. IFS= read -r líneaconserva la línea intacta, con sus espacios iniciales y finales.IFS=: read -r a b csepara por cualquier carácter, solo para ese comando. Los separadores que no son espacios delimitan campos vacíos.read -ra arrayguarda todas las palabras en un array.<<< "$var"pasa un texto como entrada. Leer desde una tubería no funciona, porque la variable se asigna en otro proceso.readdevuelve 0 si leyó una línea, 1 al final de la entrada y más de 128 si se agotó el tiempo.-e -i valorpropone un valor editable;${var:-valor}aplica uno por defecto a una respuesta vacía.- Las confirmaciones usan
[s/N], con el «no» como valor por defecto para las acciones destructivas. -soculta la entrada para contraseñas; el secreto no se muestra, no se pasa como argumento y no se exporta de más.-tpone un tiempo límite y-n1lee una sola tecla.- Las respuestas se validan en un bucle que vuelve a preguntar con un mensaje claro.
[[ -t 0 ]]indica si hay una terminal. Prioridad: argumento, entorno, pregunta y, sin terminal, valor por defecto o error.
18. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. ¿Por qué un script de automatización no debería depender de preguntar al usuario?
Porque a menudo lo ejecuta cron u otro script, sin nadie delante. Si necesita una respuesta, queda bloqueado o recibe una respuesta vacía. Los datos esenciales deben poder llegar como argumentos o variables de entorno.
2. ¿Qué hace la opción -r de read, y por qué se usa siempre?
Hace que las barras invertidas se lean como caracteres normales. Sin ella, read las elimina y altera textos como rutas de Windows o expresiones regulares.
3. ¿Qué contienen a y b después de read -r a b <<< "uno dos tres cuatro"?
a contiene uno y b contiene dos tres cuatro: la última variable recibe todo lo que sobra.
4. ¿Qué diferencia hay entre read -r x e IFS= read -r x?
La primera elimina los espacios del principio y del final de la línea. La segunda, con IFS vacío, no divide nada y guarda la línea exactamente como venía.
5. ¿Por qué se escribe IFS=: read … en lugar de IFS=: en una línea y read en la siguiente?
Porque así IFS cambia solo para ese comando. Asignarlo en una línea aparte lo cambia para todo el resto del script, y afecta a la división en palabras de cualquier expansión sin comillas posterior.
6. Con IFS=, read -r a b c <<< "x,,z", ¿qué contiene b? ¿Y si el separador fuera el espacio y el texto "x z"?
Con la coma, b queda vacía: dos comas seguidas delimitan un campo vacío. Con el espacio, los separadores se agrupan, b contiene z y c queda vacía.
7. ¿Cómo se separan en un array los directorios de PATH?
Con IFS=: read -ra dirs <<< "$PATH".
8. ¿Por qué echo hola | read -r x deja x vacía?
Porque read se ejecuta en un proceso aparte, como cada parte de una tubería. Asigna la variable en ese proceso, que termina enseguida, y el script no la ve. Se usa un here-string o una sustitución de procesos.
9. ¿Qué código de salida da read al llegar al final de la entrada, y cuál si se agota el tiempo de -t?
1 al final de la entrada, y un valor mayor que 128 (normalmente 142) al agotarse el tiempo.
10. ¿Qué hacen juntas las opciones -e e -i?
-e activa la edición de línea, con flechas y completado por Tab; -i escribe un texto inicial que el usuario puede aceptar con Enter o modificar. -i solo funciona junto con -e.
11. ¿Qué significa [s/N] en una pregunta, y por qué se usa así para borrar?
Que las respuestas posibles son sí y no, y que pulsar Enter equivale a «no», la opción en mayúscula. Para una acción destructiva, el valor por defecto debe ser el seguro, para que un Enter por costumbre no borre nada.
12. ¿Por qué es mejor pedir una contraseña con read -s que recibirla como argumento?
Porque los argumentos de un proceso pueden verlos otros usuarios con ps, y quedan en el historial de la shell. Con read -s, la contraseña no aparece en pantalla ni en la línea de comandos.
13. ¿Para qué sirve echo después de un read -s?
Para escribir un salto de línea. Como la entrada oculta tampoco muestra el Enter, el siguiente mensaje quedaría en la misma línea que el indicador.
14. ¿Qué comprueba [[ -t 0 ]], y para qué se usa en un script?
Si la entrada estándar está conectada a una terminal. Permite saber si hay alguien delante para preguntarle; si no, el script debe usar valores por defecto o terminar con un error, en lugar de quedar esperando.
15. ¿Cómo se pregunta algo al usuario si la entrada estándar del script viene de un archivo?
Leyendo directamente de la terminal: read -rp "pregunta" var < /dev/tty.
Para practicar
- Escribe un script que pida nombre y edad, valide que la edad sea un número entre 0 y 120 volviendo a preguntar si no lo es, y salude indicando el año aproximado de nacimiento.
- Prueba
readcon y sin-rescribiendoa\b\\c. Compara los resultados. - Lee la primera línea de
/etc/passwdy separa sus siete campos conIFS=:. - Separa la variable
PATHen un array y muestra cada directorio numerado. - Escribe la función
confirmarde la sección 10 y úsala en un script que copie un archivo solo si el destino no existe o si el usuario confirma sobrescribirlo. - Escribe un script que pida una contraseña dos veces con
-sy compruebe que coinciden, sin mostrarla nunca. - Prueba
read -rt 5 x; echo $?respondiendo a tiempo, sin responder, y pulsando Ctrl+D. - Ejecuta
nuevo-proyectode las tres formas: con argumento, sin argumento en la terminal y con< /dev/null. Agrégale una opción para elegir la licencia, preguntada solo si hay terminal.