20 Preguntas de Práctica de Scripting con Shell y Python con Respuestas
Todas las preguntas de práctica de Scripting con Shell y Python del Examen de práctica CompTIA Linux+, con la respuesta correcta y una breve explicación.
Comenzar examen de práctica →1. La primera línea de un script de respaldo es #!/bin/bash y el archivo se ejecuta como ./backup.sh. ¿Qué hace esa primera línea?
- A.Indica al kernel qué intérprete cargar para ejecutar el archivo, y el resto se entrega a /bin/bash.✓ Respuesta
- B.Coloca /bin/bash al inicio del PATH del script, por lo que los comandos se buscan primero ahí.
- C.Es solo un comentario para el shell, así que el script lo interpreta el shell que use quien lo llama.
- D.Marca el archivo como ejecutable por sí solo, de modo que ya no hace falta usar chmod para ello.
La línea #! debe ser la primera; el kernel la lee y ejecuta el intérprete indicado pasándole el script como argumento. Para el kernel no es un comentario, no modifica el PATH y no otorga el permiso de ejecución que la invocación directa sigue necesitando.
Ref. QB-G5MARAFuente: bash(1) manual page, Invocation and the #! interpreter directiveReportar un problema con esta pregunta
2. Al ejecutar ./deploy.sh aparece "bash: ./deploy.sh: Permission denied" y echo $? muestra 126, pero bash ./deploy.sh ejecuta el script sin problemas. ¿A qué se debe la diferencia?
- A.El directorio actual no está en el PATH, así que la forma ./ no se localiza y la otra sí se busca ahí.
- B.Al archivo le falta la línea del intérprete, así que la ejecución directa no tiene nada que cargar.
- C.El script pertenece a root, por lo que solo sudo puede ejecutarlo, aunque leerlo siga estando permitido.
- D.Al archivo le falta el bit de ejecución; chmod +x deploy.sh lo arregla, y nombrar el intérprete solo lo lee.✓ Respuesta
El estado 126 indica que el comando se encontró pero no se pudo ejecutar, lo que en un script significa que falta el permiso de ejecución; un archivo inexistente devolvería 127. Pasar el archivo a bash solo requiere permiso de lectura, por eso funciona.
Ref. QB-XM3TY8Fuente: POSIX.1 Shell Command Language, Exit Status; bash(1) exit status conventions (126 and 127)Reportar un problema con esta pregunta
3. Un script se invoca como ./sync.sh /srv/data "quarter report" --verbose. ¿Qué afirmación sobre sus parámetros posicionales es correcta?
- A.$# vale 4 porque $0 se cuenta, y "$@" se expande en cuatro palabras encabezadas por el nombre.
- B.$# vale 3 y "$@" se expande en tres palabras, así que el argumento entrecomillado queda intacto.✓ Respuesta
- C.$# vale 3, pero "$@" une los argumentos en una palabra separada por el primer carácter de IFS.
- D.$# vale 4 y "$*" mantiene cada argumento aparte, mientras que "$@" los une en una sola palabra.
$# cuenta solo los argumentos, nunca $0, de modo que aquí es 3. Entre comillas, "$@" se expande a una palabra por argumento y conserva el espacio de "quarter report"; la forma que los une con el primer carácter de IFS es "$*".
Ref. QB-F59YJ9Fuente: bash(1) manual page, Special Parameters ($#, $@ and $*)Reportar un problema con esta pregunta
4. Un script contiene f="/var/log/app log.txt" y luego if [ -f $f ]; then, y el shell informa "[: too many arguments". ¿Cuál es la causa y la corrección?
- A.El operador -f rechaza nombres con espacios, así que esas rutas deben probarse con [ -e $f ].
- B.El espacio debía escaparse al asignar, porque las comillas se quitan antes de guardar el valor.
- C.La expansión sin comillas se divide en dos palabras; escriba [ -f "$f" ] para pasar un solo argumento.✓ Respuesta
- D.El builtin [ admite un solo operando, por lo que hay que escribir [ -f $f -a -r $f ] en su lugar.
La división en palabras ocurre después de la expansión de parámetros, así que [ -f $f ] llega a test con tres operandos y este se queja. Las comillas dobles evitan esa división y mantienen la ruta como un único argumento; la asignación ya había guardado el espacio correctamente.
Ref. QB-WMQFT7Fuente: bash(1) manual page, Word Splitting and the test/[ builtinReportar un problema con esta pregunta
5. En un script, count="01". La prueba [ "$count" = "1" ] resulta falsa y [ "$count" -eq 1 ] resulta verdadera. ¿Por qué difieren?
- A.= solo funciona dentro de [[ ]] y devuelve falso en [ ], mientras que -eq es válido en ambas formas y coincide.
- B.= quita los ceros iniciales antes de comparar, así que ambas pruebas deberían ser verdaderas y falta comilla.
- C.-eq ordena sus operandos de forma léxica, así que 01 queda justo antes de 1 y el shell los considera iguales.
- D.= compara los operandos como texto y -eq los evalúa como enteros, así que 01 difiere como cadena pero vale 1.✓ Respuesta
El operador = de test compara cadenas y -eq compara aritméticamente, por lo que un número con cero inicial como 01 no es igual como texto pero sí como valor. Usar = donde se necesita una comparación numérica, o -eq sobre texto no numérico, es un error clásico de scripting.
Ref. QB-E5WMD8Fuente: bash(1) manual page, test/[ conditional expressions: string versus arithmetic operatorsReportar un problema con esta pregunta
6. Un script contiene: case "$1" in start) echo starting ;; stop|restart) echo stopping ;; *) echo usage; exit 2 ;; esac. ¿Qué ocurre al ejecutarlo con el argumento restart?
- A.La rama stop|restart y la rama *) imprimen ambas, porque * también coincide y el case sigue.
- B.La rama stop|restart imprime stopping y ;; cierra el case, así que *) no se prueba.✓ Respuesta
- C.Ninguna rama se ejecuta, porque los patrones alternativos exigen una coma entre sí.
- D.La rama *) imprime usage y sale con 2, porque el case prueba el patrón por omisión primero.
case compara los patrones de arriba abajo, ejecuta la primera lista que coincide y ;; termina esa rama para continuar después de esac. La barra | separa patrones alternativos y *) solo actúa cuando ninguno anterior coincidió.
Ref. QB-VMC5N6Fuente: POSIX.1 Shell Command Language, case conditional constructReportar un problema con esta pregunta
7. Un script de arranque contiene: until pg_isready -h db.internal >/dev/null 2>&1; do sleep 5; done. ¿Cómo se comporta el bucle?
- A.El cuerpo sigue durmiendo mientras pg_isready falla y sale al primer éxito, porque until corre si el estado no es cero.✓ Respuesta
- B.El cuerpo sigue durmiendo mientras pg_isready tiene éxito y sale al primer fallo, porque until es sinónimo de while.
- C.El cuerpo duerme una vez antes de evaluar la condición, porque until es un bucle de prueba posterior como do-while.
- D.El cuerpo se omite del todo si pg_isready falla de inmediato, porque until exige un estado cero para entrar al bucle.
until ejecuta su cuerpo mientras la condición devuelve un estado distinto de cero y se detiene en cuanto devuelve cero, justo al contrario que while. Por eso es la construcción natural para esperar a que un servicio esté disponible.
Ref. QB-D5JA87Fuente: POSIX.1 Shell Command Language, until loopReportar un problema con esta pregunta
8. Un script ejecuta: count=0; grep -c ERROR /var/log/app.log | while read -r n; do count=$n; done; echo "$count". Siempre imprime 0. ¿Por qué?
- A.read descarta los dígitos con el IFS predeterminado, así que count recibe un valor vacío.
- B.grep -c informa su cuenta por stderr, el bucle no lee nada y count conserva su valor.
- C.Cada lado de una tubería corre en su propio subshell, así que la asignación del bucle se pierde.✓ Respuesta
- D.Hay que exportar count antes del bucle para que el padre vea el valor que cambió el hijo.
Los comandos de una tubería se ejecutan en subshells y un proceso hijo no puede modificar las variables de su padre, por lo que count vuelve a 0 al terminar el bucle. Alimentar el bucle con una redirección o sustitución de proceso, como done < <(grep -c ...), lo mantiene en el shell actual; exportar solo transmite valores hacia abajo.
Ref. QB-4NUFUEFuente: bash(1) manual page, Pipelines and Command Execution Environment (subshell semantics)Reportar un problema con esta pregunta
9. Un script define tmp=/var/tmp/keep, luego prep() { tmp=$(mktemp); }, la llama y después ejecuta rm -rf "$tmp". ¿Qué cambio conserva el valor original de tmp?
- A.Añadir export tmp dentro de prep, para que el valor solo llegue al entorno de los hijos.
- B.Marcar tmp como readonly dentro de prep, para que el cambio valga solo mientras corre.
- C.Declarar local tmp dentro de prep, para que la asignación quede limitada al cuerpo.✓ Respuesta
- D.Definir prep con la palabra function, para que cada variable interna reciba su ámbito.
Las funciones del shell comparten el espacio de variables de quien las llama salvo que un nombre se declare local, así que la asignación de prep sobrescribe el tmp del script. local crea una instancia aparte durante la llamada; export solo afecta a lo que heredan los hijos y readonly haría fallar la asignación en lugar de acotarla.
Ref. QB-M52NEFFuente: bash(1) manual page, Shell Functions and the local builtinReportar un problema con esta pregunta
10. Un envoltorio ejecuta if /usr/local/bin/healthcheck.sh; then echo ok; else echo bad; fi, pero siempre toma la rama ok aunque la comprobación termine con echo "FAIL". ¿Qué debe hacer el script de comprobación?
- A.Salir de la ruta de fallo con un estado distinto de cero, porque quien llama lee ese código.✓ Respuesta
- B.Enviar el mensaje de fallo a stderr, porque el shell deduce el éxito del flujo utilizado.
- C.Imprimir FAIL en mayúsculas para filtrarlo, porque if examina la salida del comando.
- D.Asignar status=1 justo antes del mensaje, porque un script devuelve el último valor asignado.
El estado de salida es la interfaz de un script hacia quien lo llama: if, && , || y $? leen ese número, donde cero significa éxito. Como echo termina bien, un script que solo imprime FAIL sigue devolviendo 0, así que la ruta de fallo debe llamar a exit con un valor distinto de cero.
Ref. QB-XT9FRAFuente: POSIX.1 Shell Command Language, Exit Status and the exit special built-inReportar un problema con esta pregunta
11. Un script de despliegue ejecuta: mkdir -p /srv/app/rel && cp -a build/. /srv/app/rel/ || echo "deploy failed" >&2. ¿Qué descripción de la cadena es correcta?
- A.Los tres comandos se ejecutan en el orden escrito, porque && y || agrupan sin evaluar nada.
- B.cp se ejecuta solo si mkdir tiene éxito, y el mensaje sale solo cuando falla mkdir en sí.
- C.cp se ejecuta solo si mkdir tiene éxito, y el mensaje sale si cualquiera de los dos falla.✓ Respuesta
- D.cp se ejecuta pase lo que pase con mkdir, y el mensaje sale solo si falla cp, porque && agrupa.
&& ejecuta el comando siguiente solo si el estado anterior es cero, y || ejecuta su lado derecho cuando el estado de la lista AND-OR previa es distinto de cero. Por eso un mkdir fallido omite cp y aun así dispara el mensaje, y un cp fallido también lo dispara.
Ref. QB-EB4A6AFuente: POSIX.1 Shell Command Language, AND-OR lists (&& and ||)Reportar un problema con esta pregunta
12. Un script de provisión largo continúa tras un comando fallido y usa en silencio un valor vacío por un nombre de variable mal escrito. ¿Qué única línea al principio lo hace fallar cuanto antes?
- A.set -x, que imprime cada comando antes de ejecutarlo y detiene el script en el primero que devuelva error.
- B.set -euo pipefail, que aborta ante un comando fallido, una variable sin definir o un fallo en la tubería.✓ Respuesta
- C.shopt -s failglob, que termina el script tan pronto como cualquier comando devuelva un estado no nulo.
- D.set +e, que restaura el comportamiento por omisión de abandonar el script en cuanto un comando falla.
-e sale ante un estado distinto de cero no gestionado, -u convierte en error el uso de una variable sin definir y pipefail hace que una tubería devuelva el estado de su primera etapa fallida en vez de solo el último comando. set +e hace lo contrario de -e, set -x solo traza y failglob afecta a los comodines sin coincidencias.
Ref. QB-YTMSWBFuente: bash(1) manual page, set builtin options -e, -u, -x and -o pipefailReportar un problema con esta pregunta
13. Un script construye una ruta de destino equivocada sin mostrar ningún error. ¿Qué comando muestra cada orden ya expandida a medida que el shell la ejecuta?
- A.bash -n ./script.sh, que ejecuta el script mientras enumera cada asignación de variable que hace.
- B.bash -x ./script.sh, que muestra cada comando con sus expansiones justo antes de ejecutarlo.✓ Respuesta
- C.bash -v ./script.sh, que muestra cada comando solo después de ejecutarlo, ya con las expansiones.
- D.bash -e ./script.sh, que se detiene en el primer fallo y vuelca el valor de todas las variables.
La opción -x, equivalente a set -x dentro del script, escribe una traza de cada comando simple tras la expansión y precedida por PS4, lo que revela lo que realmente contenía una variable. -n solo analiza sin ejecutar, -v repite las líneas de entrada antes de expandirlas y -e cambia el manejo de errores, no la traza.
Ref. QB-FBFMBBFuente: bash(1) manual page, set -x execution tracing and shell invocation optionsReportar un problema con esta pregunta
14. Un script crea un directorio temporal con workdir=$(mktemp -d) y sale desde varios puntos, dejando directorios huérfanos cuando falla. ¿Cuál es la forma estándar de limpiarlo?
- A.Registrar trap 'rm -rf "$workdir"' EXIT justo tras crearlo, para que cualquier salida lo borre.✓ Respuesta
- B.Registrar trap 'rm -rf "$workdir"' ERR justo tras crearlo, cubriendo también los finales normales.
- C.Poner rm -rf "$workdir" en la última línea, a la que llega toda salida, incluso los fallos previos.
- D.Crearlo con mktemp -d -u, para que el kernel borre el directorio al terminar el proceso del script.
Un trap sobre EXIT ejecuta el manejador siempre que el shell termina, ya sea al llegar al final, al llamar a exit o al abortar con set -e, así que cubre todas las rutas de salida. Un trap ERR solo actúa ante fallos, una última línea se omite con salidas anticipadas y -u únicamente hace que mktemp imprima un nombre sin crear nada.
Ref. QB-VTJSD8Fuente: bash(1) manual page, trap builtin and the EXIT pseudo-signal; mktemp(1) manual pageReportar un problema con esta pregunta
15. Un script de provisión se ejecuta cada noche en todos los hosts. Añade una línea a /etc/hosts con >> y crea una cuenta con useradd svc. ¿Qué descripción del defecto es la mejor?
- A.No es legible: ambos comandos funcionan bien en cada pasada, pero nadie distingue cuál de los cambios importa más.
- B.No es atómico: los dos pasos van separados, de modo que una interrupción deja la línea del host sin su cuenta asociada.
- C.No es portable: la redirección >> escribe la línea en un archivo cuya ruta varía entre familias de distribuciones.
- D.No es idempotente: cada ejecución añade una línea repetida y useradd falla, así que el resultado depende de las pasadas.✓ Respuesta
Un script idempotente deja el sistema en el mismo estado sin importar cuántas veces se ejecute, y eso es lo que permite repetir con seguridad una tarea programada. Añadir sin condición y llamar a useradd sin comprobación rompen esa propiedad, así que el script debe verificar si la línea y la cuenta ya existen antes de cambiar nada.
Ref. QB-CBDMT7Fuente: CompTIA Linux+ exam objectives, automation and scripting domain (idempotent automated tasks); useradd(8) manual pageReportar un problema con esta pregunta
16. Un script de informes necesita una biblioteca Python de terceros en un servidor cuyo python3 proviene del gestor de paquetes de la distribución. ¿Cuál es la forma adecuada de instalarla?
- A.Ejecutar sudo pip install para que todos compartan una copia que el gestor de paquetes controle.
- B.Apuntar PYTHONPATH a un directorio con el código fuente desempaquetado de la biblioteca.
- C.Crear un entorno virtual con python3 -m venv, activarlo e instalar ahí la biblioteca con pip.✓ Respuesta
- D.Usar pip install --user con la cuenta de servicio para que el gestor registre la dependencia.
Un entorno virtual da al proyecto su propio prefijo de intérprete y su site-packages, de modo que las instalaciones con pip no chocan ni sobrescriben archivos del gestor de paquetes de la distribución, y una lista de requisitos reproduce el mismo conjunto en otra parte. Instalar con sudo pip en un intérprete gestionado puede romper herramientas del sistema, y los trucos con --user o PYTHONPATH dejan la dependencia sin registrar.
Ref. QB-WTW4K9Fuente: Python Standard Library documentation, venv module (creation of virtual environments)Reportar un problema con esta pregunta
17. Un script de Python carga miles de registros de cuentas y luego debe buscar repetidamente un registro por su nombre de usuario. ¿Qué estructura conviene más?
- A.Una lista de tuplas en el orden del archivo, porque el índice numérico llega antes a cada fila.
- B.Un diccionario indexado por el nombre, porque la clave lleva directo al registro sin recorrer.✓ Respuesta
- C.Un conjunto con los nombres de usuario, porque guarda cada usuario junto con sus demás campos.
- D.Una cadena con el archivo completo, porque un corte devuelve el registro buscado sin analizarlo.
Un dict es una asignación basada en tablas hash, así que obtener un valor por clave no depende de cuántos registros haya, mientras que encontrar un registro en una lista obliga a comparar entradas una por una. Un conjunto guarda solo las claves y no puede llevar el resto de campos de cada registro.
Ref. QB-DBRXY8Fuente: Python Standard Library documentation, built-in types: mapping type dictReportar un problema con esta pregunta
18. Un script de Python lee un archivo de configuración JSON y hoy termina con un traceback si el archivo falta o está corrupto. Debe registrar el problema y seguir con valores por omisión. ¿Qué hay que añadir?
- A.Una comprobación con os.path.exists antes de leer, que también cubre un archivo con JSON inválido dentro.
- B.Una llamada a sys.exit(0) en una cláusula else, para que un archivo ausente cuente como ejecución limpia.
- C.Un raise a secas al final del lector, que convierte el traceback en una advertencia y deja seguir al script.
- D.Un try/except en la lectura que capture OSError y json.JSONDecodeError, lo registre y use los valores base.✓ Respuesta
Capturar las excepciones concretas permite que el script decida qué hacer en lugar de terminar, y hay que atender ambos fallos: OSError si el archivo falta o no se puede leer y json.JSONDecodeError si el contenido es inválido. Comprobar la existencia es una condición de carrera y no dice nada del contenido, y un raise a secas vuelve a lanzar el error en vez de rebajarlo.
Ref. QB-3UPSEFFuente: Python Language Reference, the try statement; Python Standard Library documentation, json module exceptionsReportar un problema con esta pregunta
19. Un script de administración en Python debe ejecutar systemctl is-active nginx y ramificar según el resultado. ¿Cuál es la llamada adecuada?
- A.eval sobre la cadena del comando, ya que eval la entrega al shell y devuelve su estado de salida.
- B.os.system con el comando en una sola cadena, y leer su valor de retorno como la salida capturada.
- C.subprocess.run con shell=True y el nombre de la unidad interpolado, para que el shell cite el texto.
- D.subprocess.run con el comando como lista y capture_output=True, y ramificar según returncode.✓ Respuesta
subprocess.run es la interfaz documentada para ejecutar un comando externo: pasar una lista de argumentos evita el shell por completo y el objeto CompletedProcess devuelto trae returncode junto con stdout y stderr capturados para decidir. os.system devuelve un estado de espera, no la salida; shell=True con texto interpolado abre la puerta a la inyección de comandos; y eval evalúa expresiones de Python, no órdenes del shell.
Ref. QB-JBHMUEFuente: Python Standard Library documentation, subprocess module (subprocess.run and security considerations)Reportar un problema con esta pregunta
20. Un script de administración debe unir y comprobar rutas del sistema de archivos, leer un archivo de configuración escrito en JSON, sellar cada registro con la fecha actual y escribir mensajes por nivel en un archivo de registro. ¿Qué módulos de la biblioteca estándar corresponden a esas cuatro tareas, en ese orden?
- A.pathlib, json, datetime, logging✓ Respuesta
- B.os.path, pickle, calendar, print
- C.glob, configparser, datetime, warnings
- D.shutil, csv, time, syslog
pathlib representa las rutas del sistema de archivos como objetos con unión y comprobación de existencia, json analiza y genera texto JSON, datetime aporta fechas y marcas de tiempo, y logging emite mensajes por nivel de gravedad hacia manejadores configurables. Las otras listas mezclan módulos para copiar archivos, texto tabular, serialización de objetos o comodines, que no resuelven esas cuatro tareas.
Ref. QB-4K8XW5Fuente: Python Standard Library documentation, pathlib, json, datetime and logging modulesReportar un problema con esta pregunta
Otros temas de este examen
Preguntas de práctica redactadas según los objetivos publicados del examen CompTIA Linux+ y la práctica estándar de administración de Linux. CompTIA y Linux+ son marcas de CompTIA, y Linux es una marca registrada de Linus Torvalds; este sitio no está afiliado ni respaldado por CompTIA. El examen real combina preguntas de opción múltiple con preguntas basadas en desempeño que piden ejecutar una tarea en un entorno simulado: eso no puede reproducirse en un formato de cuatro opciones, así que este banco cubre la mitad teórica y conviene practicar en un sistema real en paralelo. CompTIA revisa y numera las versiones de los objetivos periódicamente: confirma los objetivos, el código de examen y los requisitos vigentes con CompTIA antes de examinarte. Sobre la certificación CompTIA Linux+ →