Hola HumanOS. Con esta serie de artículos se pretende que el usuario que tenga alguna idea de programación y que necesite de algún tipo de referencia para empezar a programar en este lenguaje script, tenga por donde guiarse.

Bash

En este artículo veremos:

  • Crear un archivo “.sh”.
  • Variables.
  • Scripts básicos.
  • Entradas y salidas, Operadores de redirección.

Primero, aclarar lo que es un Script:

Script: En informática, un script, archivo de órdenes, archivo de procesamiento por lotes o guión, es un programa usualmente simple, que por lo regular se almacena en un archivo de texto plano. Los script son casi siempre interpretados, pero no todo programa interpretado es considerado un script. El uso habitual de los scripts es realizar diversas tareas como combinar componentes, interactuar con el sistema operativo o con el usuario. Por este uso es frecuente que los shells sean a la vez intérpretes de este tipo de programas.

Los archivos script suelen ser identificados por el sistema a través uno de los siguientes encabezamientos en el contenido del archivo, conocido como shebang:

#!/bin/bash
#!/bin/ksh
#!/bin/csh

Estos archivos también pueden ser identificados a través de la extensión “.sh”, aunque esta suele ser añadida más bien para identificarlos sin tener que abrirlos, ya que casi todos los sistemas no necesitan dicha extensión para ejecutar el script.

Primero deben crear un archivo con extensión “.sh”. Para hacerlo desde la terminal solo deben estar en la carpeta en la cual quieren crear el archivo y poner:

 nano nombreDelArchivo.sh

Presionan “Enter” y luego pegan el texto de abajo (con “Ctrl + Shift + V”):

#!/bin/bash
echo Hola Mundo

(echo: es un comando para la impresión de un texto en pantalla )

Luego guardan los cambios efectuados (“Ctrl + O”, “Enter” para confirmar y luego “Ctrl + X” para salir). Para ejecutar el Script basta con poner en la terminal:

bash nombreDelArchivo.sh

Este script tiene sólo dos líneas. La primera le indica al sistema qué programa usar para ejecutar el fichero. La segunda línea es la única acción realizada por este script, que imprime ’Hola Mundo’ en la terminal.

Variables:

Puede usar variables como en cualquier otro lenguaje de programación. No existen tipos de datos. Una variable de bash puede contener un número, un caracter o una cadena de caracteres.

No necesita declarar una variable. Se creará sólo con asignarle un valor a su referencia.

Ejemplo ‘Hola Mundo’ con variables:

#!/bin/bash
STR="Hola Mundo!"
echo $STR

La segunda línea crea una variable llamada STR y le asigna la cadena ‘¡Hola Mundo!’. Luego se recupera el VALOR de esta variable poniéndole un ‘$‘ al principio. Por favor, tenga en cuenta (¡inténtelo!) que si no usa el signo ‘$‘, la salida del programa será diferente, y probablemente no sea lo que usted quería.

Las variables locales pueden crearse utilizando la palabra clave local.

#!/bin/bash
HOLA=Hola
echo $STR
function hola {
    local HOLA=Mundo
    echo $HOLA
}
echo $HOLA
hola
echo $HOLA

Este ejemplo debería bastar para mostrarle el uso de una variable local.

Variables con tipo:

Aunque en los primeros shells las variables sólo podían contener cadenas de caracteres, después se introdujo la posibilidad de asignar atributos a las variables que indican, por ejemplo, que son enteras o de sólo lectura. Para fijar los atributos de las variables tenemos el comando interno declare, el cual tiene la siguiente sintaxis:

declare [-afFirx] [-p] name[=value] ...

La siguiente tabla describe las opciones que puede recibir este comando. Una peculiaridad de este comando es que para activar un atributo se precede la opción por un guión.

-a La variable es de tipo array
-f Mostrar el nombre e implementación de las funciones
-F Mostrar sólo el nombre de las funciones
-i La variable es de tipo entero
-r La variable es de sólo lectura
-x Exporta la variable (equivalente a export)

Si escribimos declare sin argumentos nos muestra todas las variables de entorno. Si usamos la opción -f nos muestra sólo los nombres de funciones y su implementación, y si usamos la opción -F nos muestra sólo los nombres de las funciones existentes.

Las variables que se declaran con declare dentro de una función son variables locales a la función, de la misma forma que si hubiésemos usado el modificador local.

La opción -i nos permite declarar una variable de tipo entero, lo cual permite que podamos realizar operaciones aritméticas con ella. Por ejemplo, si usamos variables de entorno normales para realizar operaciones aritméticas:

var1=5
var2=4
resultado=$var1*$var2
echo $resultado #5*4

Sin embargo si ahora usamos variables de tipo entero:

declare -i var1=5
declare -i var2=4
declare -i resultado
resultado=$var1*$var2
echo $resultado #20

Para que la operación aritmética tenga éxito no es necesario que declaremos como enteras a var1 y var2, basta con que recojamos el valor en la variable resultado declarada como entera. Es decir, podremos hacer:

resultado=4*6
echo $resultado #24

Incluso podemos recoger resultados de operaciones con variables inexistentes:

resultado=4*$var_inexistente
echo $resultado #0

Podemos saber el tipo de una variable con la opción -p. Por ejemplo:

declare -p resultado
declare -i resultado="24"

La opción -x es equivalente a usar el comando export sobre la variable. Ambas son formas de exportar una variable de entorno.

La opción -r declara a la variable como de sólo lectura, con lo que a partir de ese momento no podremos modificarla ni ejecutar unset sobre ella.

Existe otro comando interno llamado readonly que nos permite declarar variables de sólo lectura, pero que tiene más opciones que declare -r.

Muchas veces se ataca un sistema modificando una función que se sabe que va a ejecutar un script en modo súperusuario (haciendo que la función haga algo distinto, o algo más de lo que hacía originalmente). Para evitar este ataque las funciones que van a ejecutarse en modo súperusuario se deben definir sólo dentro del script que las usa, aunque a veces se necesitan llamar desde fuera y es recomendable protegerlas con la opción -r, ya que una vez que una función se marca como de sólo lectura ya no se puede quitar este permiso.

Entradas y Salidas, Operadores de redirección:

UNIX está basado en una idea muy simple pero muy útil: Tratar todas las entradas y salidas como streams (flujos) de bytes. Cada programa va a tener asociadas siempre una entrada estándar (por defecto el teclado), una salida estándar (por defecto la consola), y una salida de errores estándar (por defecto también la consola).

Si queremos, podemos cambiar la entrada estándar para que el programa reciba datos de un fichero usando el operador de redirección <. Por ejemplo el comando cat, si no recibe argumentos, lee del teclado por la entrada estándar y lo pasa a la salida estándar:

cat
Esto es una linea acabada en intro
Esto es una linea acabada en intro
^D

(cat: (por concatenar) es usado para concatenar y mostrar archivos, este escribirá a la salida estándar el contenido de cada uno de los archivos dados como argumentos, en el mismo orden en el que fueron dados)

Podemos indicar el final de un stream desde el teclado con la combinación de teclas “Ctrl+D” como se muestra en el ejemplo. Podemos cambiar la entrada estándar de cat para que lea de un fichero con:

cat < clave.h
#ifndef CLAVE_H_
·····

En el caso concreto del comando cat, también puede recibir como argumento el nombre del fichero a pasar a la salida estándar, con lo que en el caso del comando cat nos podríamos haber ahorrado el operador <:

cat clave.h
#ifndef CLAVE_H_
·····

UNIX dispone de un gran número de comandos que leen de la entrada estándar, realizan una operación con el texto, y escriben en la salida estándar (o en la salida de errores si se produce un error): cat, grep, soft, cut, sed, tr,…

El operador de redirección de salida > permite cambiar la salida estándar de un comando, por ejemplo:

date > ahora

Envía el día y hora actuales al fichero ahora.

También podemos cambiar a la vez la entrada y salida estándar de un programa usando ambos operadores de redirección. Por ejemplo:

cat < ficheroa > ficherob

También podemos cambiar la salida de errores estándar con el operador de redirección 2>. Por ejemplo:

cat < ficheroa > ficherob 2>errores

Copia el ficheroa en el ficherob, y si se produce algún error lo escribe en el fichero errores.

Si no queremos sobrescribir un fichero de salida sino añadir el contenido al final podemos usar el operador de redirección >> para la salida estándar o 2>> para los errores estándar. Por ejemplo:

ls p* >>ficheros 2>>errores

(ls: muestra un listado ordenado alfabéticamente con los archivos y directorios de un determinado directorio )

Añadiría los ficheros que lista ls al fichero ficheros, y si se produjesen errores los añadiría al fichero errores. El operador de redirección 2>> es especialmente útil para almacenar los conocidos logs de errores.

Muchas veces no se quiere que un programa muestre mensajes en la consola del usuario, en este caso es muy común redirigir su salida estándar y salida de errores estándar al fichero /dev/null:

gcc *.cpp > /dev/null 2> /dev/null

Y hasta aquí este artículo, en el próximo profundizaremos un poco más… Hasta entonces.

Fuentes:

  • Wikipedia (es) (https://es.wikipedia.org/).
  • Programación en BASH – COMO de introducción (por Mike G, julio del 2000) disponible en dynamo.com.ar.
  • El shell Bash (por Fernando López Hernández, Septiembre 2005) disponible en macprogramadores.org.