Comprensión y aprendizaje de las secuencias de comandos de shell básicas y la resolución de problemas del sistema de archivos Linux - Parte 10


Linux Foundation lanzó la certificación LFCS ( Linux Foundation Certified Sysadmin ), una nueva iniciativa cuyo propósito es permitir que las personas en todas partes (y en cualquier lugar) obtengan la certificación de básico a intermedio. soporte operativo para sistemas Linux, que incluye soporte de sistemas y servicios en ejecución, junto con monitoreo y análisis generales, además de una toma de decisiones inteligente cuando se trata de plantear problemas a los equipos de soporte superiores.

Vea el siguiente video que le brinda una introducción al Programa de Certificación de la Fundación Linux.

Este es el último artículo (Parte 10) de la presente serie larga de 10 tutoriales. En este artículo, nos centraremos en las secuencias de comandos de shell básicas y la resolución de problemas de los sistemas de archivos Linux. Ambos temas son obligatorios para el examen de certificación LFCS.

Comprensión de terminales y carcasas

Primero aclaremos algunos conceptos.

  1. Un shell es un programa que toma comandos y los entrega al sistema operativo para que los ejecute.
  2. Una terminal es un programa que nos permite, como usuarios finales, interactuar con el shell. Un ejemplo de terminal es el terminal GNOME, como se muestra en la imagen de abajo.

Cuando iniciamos un shell por primera vez, presenta un símbolo del sistema (también conocido como línea de comando), que nos dice que el shell está listo para comenzar a aceptar comandos desde su dispositivo de entrada estándar, que generalmente es el teclado.

Es posible que desee consultar otro artículo de esta serie (Usar comando para crear, editar y manipular archivos - Parte 1) para revisar algunos comandos útiles.

Linux proporciona una variedad de opciones para shells, las siguientes son las más comunes:

Bash significa Bourne Again SHell y es el shell predeterminado del proyecto GNU. Incorpora funciones útiles del shell Korn (ksh) y del shell C (csh), que ofrecen varias mejoras al mismo tiempo. Este es el shell predeterminado utilizado por las distribuciones cubiertas en la certificación LFCS, y es el shell que usaremos en este tutorial.

Bourne SHell es el shell más antiguo y, por lo tanto, ha sido el shell predeterminado de muchos sistemas operativos similares a UNIX durante muchos años.

Korn SHell es un shell de Unix que fue desarrollado por David Korn en Bell Labs a principios de la década de 1980. Es compatible con versiones anteriores del shell Bourne e incluye muchas características del shell C.

Un script de shell es nada más y nada menos que un archivo de texto convertido en un programa ejecutable que combina los comandos que ejecuta el shell uno tras otro.

Secuencias de comandos de shell básicas

Como se mencionó anteriormente, un script de shell nace como un archivo de texto sin formato. Por lo tanto, se puede crear y editar con nuestro editor de texto preferido. Es posible que desee considerar el uso de vi/m (consulte Uso del editor vi - Parte 2 de esta serie), que presenta resaltado de sintaxis para su conveniencia.

Escriba el siguiente comando para crear un archivo llamado myscript.sh y presione Entrar.

# vim myscript.sh

La primera línea de un script de shell debe ser la siguiente (también conocida como shebang ).

#!/bin/bash

Le “ le dice ” al sistema operativo el nombre del intérprete que debe usarse para ejecutar el texto que sigue.

Ahora es el momento de agregar nuestros comandos. Podemos aclarar el propósito de cada comando, o todo el script, agregando comentarios también. Tenga en cuenta que el shell ignora las líneas que comienzan con un signo de almohadilla # (comentarios explicativos).

#!/bin/bash
echo This is Part 10 of the 10-article series about the LFCS certification
echo Today is $(date +%Y-%m-%d)

Una vez que se ha escrito y guardado el script, debemos hacerlo ejecutable.

# chmod 755 myscript.sh

Antes de ejecutar nuestro script, necesitamos decir algunas palabras sobre la variable de entorno $PATH . Si corremos

echo $PATH

desde la línea de comando, veremos el contenido de $PATH: una lista de directorios separados por dos puntos que se buscan cuando ingresamos el nombre de un programa ejecutable. Se denomina variable de entorno porque es parte del entorno del shell: un conjunto de información que está disponible para el shell y sus procesos secundarios cuando se inicia el shell por primera vez.

Cuando escribimos un comando y presionamos Enter, el shell busca en todos los directorios listados en la variable $PATH y ejecuta la primera instancia que se encuentra. Veamos un ejemplo,

Si hay dos archivos ejecutables con el mismo nombre, uno en /usr/local/bin y otro en /usr/bin , se ejecutará el del primer directorio. primero, mientras que el otro será ignorado.

Si no hemos guardado nuestro script dentro de uno de los directorios listados en la variable $PATH , necesitamos agregar ./ al nombre del archivo para poder ejecutarlo. De lo contrario, podemos ejecutarlo como lo haríamos con un comando normal.

# pwd
# ./myscript.sh
# cp myscript.sh ../bin
# cd ../bin
# pwd
# myscript.sh

Siempre que necesite especificar diferentes cursos de acción a tomar en un script de shell, como resultado del éxito o fracaso de un comando, utilizará la construcción if para definir tales condiciones. Su sintaxis básica es:

if CONDITION; then 
	COMMANDS;
else
	OTHER-COMMANDS 
fi

Donde CONDITION puede ser una de las siguientes (aquí solo se citan las condiciones más frecuentes) y se evalúa como verdadera cuando:

  1. [-a archivo] → el archivo existe.
  2. [-d archivo] → el archivo existe y es un directorio.
  3. [-f archivo] → el archivo existe y es un archivo normal.
  4. [-u archivo] → el archivo existe y su bit SUID (establecer ID de usuario) está establecido.
  5. [-g archivo] → el archivo existe y su bit SGID está configurado.
  6. [-k archivo] → el archivo existe y su bit adhesivo está configurado.
  7. [-r archivo] → el archivo existe y es legible.
  8. [-s file] → el archivo existe y no está vacío.
  9. [-w archivo] → el archivo existe y se puede escribir.
  10. [-x archivo] es verdadero si el archivo existe y es ejecutable.
  11. [string1 u003d string2] → las cadenas son iguales.
  12. [string1! u003d string2] → las cadenas no son iguales.

[int1 op int2] debe formar parte de la lista anterior, mientras que los elementos que siguen (por ejemplo, -eq -> es verdadero si int1 es igual a int2 .) debe ser una lista " hijos " de [ int1 op int2 ] donde op es uno de los siguientes operadores de comparación.

  1. -eq -> es verdadero si int1 es igual a int2.
  2. -ne -> verdadero si int1 no es igual a int2.
  3. -lt -> verdadero si int1 es menor que int2.
  4. -le -> verdadero si int1 es menor o igual que int2.
  5. -gt -> verdadero si int1 es mayor que int2.
  6. -ge -> verdadero si int1 es mayor o igual que int2.

Este bucle permite ejecutar uno o más comandos para cada valor en una lista de valores. Su sintaxis básica es:

for item in SEQUENCE; do 
		COMMANDS; 
done

Donde elemento es una variable genérica que representa cada valor en SECUENCIA durante cada iteración.

Este bucle permite ejecutar una serie de comandos repetitivos siempre que el comando de control se ejecute con un estado de salida igual a cero (con éxito). Su sintaxis básica es:

while EVALUATION_COMMAND; do 
		EXECUTE_COMMANDS; 
done

Donde EVALUATION_COMMAND puede ser cualquier comando que pueda salir con un estado de éxito ( 0 ) o error (que no sea 0) y EXECUTE_COMMANDS puede ser cualquier programa, script o construcción de shell, incluidos otros bucles anidados.

Demostraremos el uso de la construcción if y el ciclo for con el siguiente ejemplo.

Creemos un archivo con una lista de servicios que queremos monitorear de un vistazo.

# cat myservices.txt

sshd
mariadb
httpd
crond
firewalld

Nuestro script de shell debería verse así.

#!/bin/bash

# This script iterates over a list of services and
# is used to determine whether they are running or not.

for service in $(cat myservices.txt); do
    	systemctl status $service | grep --quiet "running"
    	if [ $? -eq 0 ]; then
            	echo $service "is [ACTIVE]"
    	else
            	echo $service "is [INACTIVE or NOT INSTALLED]"
    	fi
done

1). El bucle for lee el archivo myservices.txt un elemento de LIST a la vez. Ese único elemento se denota mediante la variable genérica denominada servicio. La LISTA se completa con la salida de,

# cat myservices.txt

2). El comando anterior está entre paréntesis y precedido por un signo de dólar para indicar que debe evaluarse para completar la LISTA sobre la que iteraremos.

3). Para cada elemento de LIST (es decir, cada instancia de la variable de servicio), se ejecutará el siguiente comando.

# systemctl status $service | grep --quiet "running"

Esta vez necesitamos preceder nuestra variable genérica (que representa cada elemento en LIST ) con un signo de dólar para indicar que es una variable y, por lo tanto, se debe usar su valor en cada iteración. La salida luego se canaliza a grep.

El indicador –quiet se utiliza para evitar que grep muestre en la pantalla las líneas donde aparece la palabra en ejecución. Cuando eso sucede, el comando anterior devuelve un estado de salida de 0 (representado por $? en la construcción if), verificando así que el servicio se está ejecutando.

Un estado de salida diferente a 0 (lo que significa que la palabra en ejecución no se encontró en la salida de systemctl status $service ) indica que el servicio no está corriendo.

Podríamos ir un paso más allá y verificar la existencia de myservices.txt incluso antes de intentar ingresar al bucle for.

#!/bin/bash

# This script iterates over a list of services and
# is used to determine whether they are running or not.

if [ -f myservices.txt ]; then
    	for service in $(cat myservices.txt); do
            	systemctl status $service | grep --quiet "running"
            	if [ $? -eq 0 ]; then
                    	echo $service "is [ACTIVE]"
            	else
                    	echo $service "is [INACTIVE or NOT INSTALLED]"
            	fi
    	done
else
    	echo "myservices.txt is missing"
fi

Es posible que desee mantener una lista de hosts en un archivo de texto y usar una secuencia de comandos para determinar de vez en cuando si se pueden hacer ping o no (siéntase libre de reemplazar el contenido de myhosts e intentarlo usted mismo ).

El comando read shell incorporado le dice al bucle while que lea myhosts línea por línea y asigna el contenido de cada línea a la variable host, que luego se pasa al comando ping .

#!/bin/bash

# This script is used to demonstrate the use of a while loop

while read host; do
    	ping -c 2 $host
done < myhosts

Leer también :

  1. Aprenda las secuencias de comandos de Shell: una guía para principiantes y administradores de sistemas
  2. 5 scripts de shell para aprender a programar en shell

Solución de problemas del sistema de archivos

Aunque Linux es un sistema operativo muy estable, si falla por alguna razón (por ejemplo, debido a un corte de energía), uno (o más) de sus sistemas de archivos no se desmontarán correctamente y, por lo tanto, se verificará automáticamente en busca de errores cuando Linux se reinicia.

Además, cada vez que el sistema arranca durante un arranque normal, siempre comprueba la integridad de los sistemas de archivos antes de montarlos. En ambos casos, esto se realiza utilizando una herramienta llamada fsck (" verificación del sistema de archivos ").

fsck no solo verificará la integridad de los sistemas de archivos, sino que también intentará reparar los sistemas de archivos corruptos si se le indica que lo haga. Dependiendo de la gravedad del daño, fsck puede tener éxito o no; cuando lo hace, las partes recuperadas de los archivos se colocan en el directorio perdido + encontrado , ubicado en la raíz de cada sistema de archivos.

Por último, pero no menos importante, debemos tener en cuenta que también pueden ocurrir inconsistencias si intentamos quitar una unidad USB cuando el sistema operativo todavía está escribiendo en ella, e incluso pueden provocar daños en el hardware.

La sintaxis básica de fsck es la siguiente:

# fsck [options] filesystem

Para verificar un sistema de archivos con fsck, primero debemos desmontarlo.

# mount | grep sdg1
# umount /mnt
# fsck -y /dev/sdg1

Además del indicador -y , podemos usar la opción -a para reparar automáticamente los sistemas de archivos sin hacer preguntas y forzar la verificación incluso cuando el sistema de archivos parece limpio.

# fsck -af /dev/sdg1

Si solo estamos interesados en averiguar qué está mal (sin intentar arreglar nada por el momento), podemos ejecutar fsck con la opción -n , que generará los problemas del sistema de archivos en la salida estándar.

# fsck -n /dev/sdg1

Dependiendo de los mensajes de error en la salida de fsck, sabremos si podemos intentar resolver el problema nosotros mismos o escalarlo a los equipos de ingeniería para realizar más verificaciones en el hardware.

Resumen

Hemos llegado al final de esta serie de 10 artículos en la que hemos intentado cubrir las competencias básicas del dominio necesarias para aprobar el examen LFCS .

Por razones obvias, no es posible cubrir todos los aspectos de estos temas en un solo tutorial, y es por eso que esperamos que estos artículos lo hayan puesto en el camino correcto para probar cosas nuevas usted mismo y continuar aprendiendo.

Si tiene alguna pregunta o comentario, siempre será bienvenido, así que no dude en escribirnos a través del formulario a continuación.