1. Tecnología
  2. »
  3. GNU/Linux
  4. »
  5. Linux

#!1 Bash desde cero



GNU/Linux es uno de los sistemas operativos más poderosos y flexibles del mundo. En la computación moderna, no existe lugar donde no sea utilizado -desde servidores, laptops, smartphones, tablets a supercomputadoras, todo corre Linux. Aún cuando en la actualidad existan interfaces gráficas modernas y atractivas, el shell sigue siendo la manera más flexible y efectiva de interactuar con el sistema.

Además de ejecutar comandos de manera individual, un shell puede seguir comandos desde un script, lo que nos provee una manera sencilla de automatizar tareas; preparar reportes, enviar e-mails, programar mantenimientos, y mucho, mucho más. La idea es que este sea el primero de una extensa lista de posts cuyo objetivo general es exponer de manera sistemática posibles usos en situaciones de la vida real de comandos y shell scripts. Pueden ser utilizados como mera referencia, o como inspiración para escribir scripts propios. Los tópicos van desde manipulación de texto a tareas administrativas sobre sistemas y redes.

La fuente es un compendio de libros, revistas electrónicas, y marcadores que aún consulto, pasado por el filtro de mi criterio y mis usos del idioma, dado que todo está en inglés. Como nota personal, no soy programador ni me dedico profesionalmente (o "amateurmente" ) a la informática, y si bien estudio ciencias de la computación no soy un tecnólogo. Tengo una agenda, como todos, pero eso queda para otro día.

Intro

Los sistemas basados en Unix son, en términos de diseño, sistemas operativos increíbles. Incluso luego de tantas décadas, la arquitectura derivada de Unix sigue siendo uno de los mejores diseños. Una de las características importantes de esta arquitectura es la interface de línea de comando, o shell. El shell como entorno ayuda al usuario a interactuar y acceder a funciones clave del sistema operativo. El término scripting se torna relevante en este contexto. El scripting es usualmente soportado por lenguajes de programación cuya implementación está ligada al intérprete. Los shell scripts son archivos en los que escribimos una secuencia de comandos que necesitamos correr y que son ejecutados mediante el shell.

Obviamente, nosotros hablaremos siempre de Bash (Bourne Again Shell), que es el entorno de shell por defecto en la amplia mayoría de los sistemas GNU/Linux.
El objetivo inicial de este post es un primer acercamiento a un entorno de shell (en oposición a "interfaz gráfica" ) y que empecemos a incorporar en nuestro arsenal las funcionalidades básicas que el shell nos ofrece. Los comandos son escritos y ejecutados en un terminal del shell. Al abrir un terminal, un prompt estará disponible, el cuál en general tendrá el siguiente formato:

[email protected] $

O también:

[email protected] #

O simplemente $ o #.
$ representa usuarios regulares y # representa al usuario administrativo root. Root es el usuario que concentra el máximo nivel de permisos en un sistema Linux.

En general es una mala idea usar directamente el shell como usuario root (administrador) para realizar tareas. Esto es porque el potencial daño que pueden ocasionar errores de tipeo (como mínimo) es proporcional al nivel de privilegios del shell. Entonces, como práctica es recomendable entrar como usuario regular (el shell va a denotar esto con un $ en el prompt, y con # cuando sea root), y usar herramientas como 'sudo' para ejecutar comandos sensibles. Utilizar un comando mediante sudo correrá el comando como root.

Un shell script es un archivo de texto que en general comienza con un shebang:

#!/bin/bash

Shebang es la línea donde #! precede la ruta del intérprete. /bin/bash es la ruta de intérprete de comandos para Bash.

Ejecutar un script puede hacerse de dos maneras. Podemos o bien correr el script como argumento del comando bash en la línea de comandos, o bien otorgar permisos de ejecución al script, de modo tal que se vuelve un ejecutable.

En el primer caso, corremos el script utilizando el nombre de archivo como argumento en la línea de comandos (el texto que comienza con # es un comentario, no hay que escribirlo):

$ bash script.sh # Asumiendo que el script está en el directorio actual

O:

$ bash /home/ruta/script.sh # Utilizando la ruta completa a script.sh

Si corremos un script como argumento en la línea de comandos para bash, el shebang en el script no es necesario.

Ahora bien, podemos utilizar el shebang para lograr que el script corra por sí mismo. Para esto, debemos otorgarle permisos de ejecución; entonces, correrá utilizando la ruta del intérprete que esté fijada a continuación del #! en el shebang. Los permisos se fijan de la siguiente manera:

$ chmod a+x script.sh

Este comando otorga (+) al archivo script.sh el permiso de ser ejecutado (x) por todos los usuarios (a). El script se ejecuta de la siguiente manera:

$ ./script.sh # ./ representa el directorio actual

O:

$ /home/ruta/script.sh # Ruta completa al script

El kernel leerá la primera línea y verá que el shebang es #!/bin/bash. Luego, identificará /bin/bash y ejecutará el script internamente como:

$ /bin/bash script.sh

Cuando un shell es abierto, primero que nada ejecuta una serie de comandos para definir varios parámetros como el texto del prompt, colores, y mucho más. Este conjunto de comandos es leído desde un shell script en ~/.bashrc (o ~/.bash_profile para shells de inicio de sesión) localizados en el directorio principal del usuario. Bash también guarda un historial de comandos utilizados por el usuario. Está disponible en el archivo ~/.bash_history.

~ denota el directorio principal del usuario, que usualmente es /home/usuario donde usuario es el nombre de usuario o /root para el usuario root.

Un shell de inicio de sesión o login shell, es el shell al que accedemos al loguear en una máquina. Sin embargo, si abrimos un shell mientras estamos logueados dentro de un entorno gráfico (como GNOME, KDE, XFCE, etc.), ese no es un login shell.

En Bash, cada comando o secuencia de comando está delimitada por un punto y coma ( ; ) o una nueva línea. Por ejemplo:

$ cmd1 ; cmd2

Esto es equivalente a:

$ cmd1
$ cmd2


Por último, el caracter # es utilizado para denotar el inicio de comentarios que no serán procesados. La sección de un comentario inicia con # y se extiende hasta el final de línea. Los líneas de comentarios son utilizadas mayormente para proveer comentarios acerca del código en el archivo o para evitar que una línea de código sea ejecutada.

Estética y funcionalidad






Antes de comenzar, utilizando lo visto hasta ahora haremos pequeños ajustes en .bashrc, de modo que el prompt en nuestro terminal se vea como en las screens.
El terminal es una utilidad mediante la cual el usuario interactúa con el entorno del shell.

Cómo lo hacemos...

Esto es enteramente opcional, pero sumamente útil, y de cualquier manera, siempre podremos volver atrás. Utilizaremos un editor de texto simple, mi recomendación es gedit o leafpad (desde el cual escribo). Abrimos un terminal y procedemos a abrir .bashrc con el editor:

$ gedit .bashrc

Primero, descomentamos la línea force_color_prompt=yes, borrando el caracter #:



Luego, unas líneas más abajo, dentro del bloque if ["$color_prompt" = yes ], comentamos la primera línea que empieza con PS1='..., es decir, agregamos el caracter # al inicio de la línea. Inmediatamente debajo, pegamos una de las líneas de código que acompañan las screens que dieron inicio a la sección (links):



Guardamos y cerramos. Lo que hicimos fue habilitar color en el prompt, comentamos la línea con los parámetros por defecto del prompt con colores y agregamos nuestra configuración. Por último, escribimos:

$ source .bashrc

y abremos recargado los parámetros.

En las próximas sección la sintáxis de la línea de código que acaban de copiar será evidente, y podrá ser modificada sin inconvenientes.
Podemos reemplazar ${debian_chroot:+($debian_chroot)} por la variable del entorno que corresponda a la distribución que utilicemos; dicha variable estará explícita en el PS1 por defecto.

Imprimir texto en pantalla

Imprimir texto en el terminal es una tarea básica que cualquier shell script y la mayoría de las utilidades necesitan realizar regularmente. Podemos realizarla mediante varios métodos y bajo diferentes formatos.

Cómo lo hacemos...

echo es el comando básico para imprimir en la terminal.
echo agrega una nueva línea al final de cada llamado por defecto:

$ echo "Bienvenido a Bash"
Bienvenido a Bash


Simple. Introduciendo texto entre comillas dobles junto al comando echo, imprimimos el texto en el terminal.
De manera similar, texto sin comillas dobles también devuelve la misa salida:

$ echo Bienvenido a Bash
Bienvenido a Bash


Otra manera de realizar la misma tarea es utilizando comillas simples:

$ echo 'texto'

En una primera instancia estos métodos pueden parecer similares, pero algunos de ellos tienen propósitos específicos y efectos secundarios también. Consideremos el siguiente comando:

$ echo "no es posible introducir la exclamáción !- entre comillas dobles"

Nos devolverá la siguiente salida:

bash: !: event not found

Luego, si queremos imprimir caracteres especiales como !, no los utilizaremos con comillas dobles, o utilizaremos el caracter especial de escape () como prefijo, es decir:

$ echo Hola mundo !

O:

$ echo 'Hola mundo !'

O:

$ echo "Hola mundo \!" # Caracter de escape \ prefijado

Los efectos secundarios de cada método son los siguientes:

  • Cuando usamos echo sin comillas, no podemos usar el punto y coma ( ; ), dado que el mismo actúa delimitando comandos en el shell de Bash.
  • echo hola; hola toma echo hola como un comando y al segundo hola como segundo comando
  • Las variables de sustitución, que serán discutidas en el siguiente post pero ya vimos al modificar los parámetros del prompt, no funcionarán con comillas simples


Otro comando utilizado para imprimir en pantala es printf. Utiliza los mismos argumentos que el printf del lenguaje de programación C. Por ejemplo:

$ printf "Hola mundo"

printf toma texto entrecomillado o argumentos delimitados por espacios. Podemos dar formato al texto con printf. Podemos especificar el ancho de la cadena, alineación a la izquierda o derecha, y demás. Por defecto, printf no genera una nueva línea como el comando echo. Debemos especificar una nueva línea cuando sea requerido, como se muestra en el siguiente script:



Ejecutando el script, nos devolverá el texto formateado:



Cómo funciona

%s, %c, %d y %f son caracteres de sustitución, el argumento se ubica luego de las cadenas de formato entrecomilladas.

%-5s puede ser descripto como una cadena de sustitución con alineación a la izquierda (-) con ancho igual a 5. Si - no está especificado, la cadena será alineada a la derecha. El ancho especifica el número de caracteres reservados para esa variable. Para Nombre, el ancho reservado es 10. Luego, todo nombre va a estar dentro de los 10 caracteres de ancho reservados y el resto de los lugares vacíos serán rellenados con espacios en blanco hasta llegar a los 10 caracteres del total.

Para números de punto flotante, podemos agregar parámetros adicionales para redondear la cantidad de decimales luego de la coma.

Para Marcas, el formato que le dimos fue %-4.2f, donde .2 especifica redondear a dos decimales. Notar que al final de cada línea de cadena de formato, se necesita agregar una nueva línea (\n).

Hay más...

Al usar flags en echo y printf, siempre asegurarse de que los flags aparezcan antes que cualquier cadena, de otra forma Bash los considerará como otras cadenas.

Evitando una nueva línea en echo

Por defecto, echo agrega una nueva línea al final del texto de salida. Esto puede ser evitado usando el flag -n. echo también acepta secuencias de escape en cadenas entre comillas dobles como argumentos. Al usar secuencias de escape, usar echo como echo -e "cadena que contiene secuencias de escape". Por ejemplo:



Salida con colores

Producir una salida con colores en la terminal es muy interesante y se consigue utilizando secuencias de escape. ¡Lo hicimos al personalizar el prompt!

Los colores son representados por códigos, por ejemplo, reset = 0, negro = 30, rojo = 31, verde = 32, amarillo = 33, azul = 34, magenta = 35, cyan = 36, y blanco = 37.

Para imprimir texto en color, introducimos el siguiente comando:



Clarísimo. \e[1;31m es la cadena de escape que fija el color rojo y \e[0m reinicia el color negro. Se puede reemplazar 31 por cualquier otro color.

Para un fondo coloreado, reset = 0, negro = 40, rojo = 41, verde = 42, amarillo = 43, azul = 44, magenta = 45, cyan = 46, y blanco = 47, son los códigos de color usados en general.

Para imprimir con fondo coloreado, introducir el comando siguiente:



Eso es todo. Los próximos temas son variables de entorno, descriptores de archivos y algo más lúdico con matemática y C, siempre pensado para todas y todos.

¡Que les garúe finito!



NOTA: el backslash ( \ ) funciona mal en T!, y se deben escribir dos para que salga uno. Si llegan a ver dos juntos, es uno.
0
0
0
0No hay comentarios