Trucos de programación en shell

Vemos a continuación ua serie de ejemplo genéricos para resolver cuestiones que se presentan en la programación de shell con cierta frecuencia

Script con número variable de argumentos:

Este programa de shell pretende ejecutar una serie de instrucciones para cada uno de los argumentos que se le pasen desde la línea de órdenes.

for i in $*
do
instrucciones
done
              

Por ejemplo, hacemos un script que mueva todos los ficheros pasado como argumento al directorio ./papelera:

for i in $*
do
if [ -f $i ]
then
mv $i ./papelera
fi
done
              

Script para aplicar una serie de órdenes a cada fichero de un directorio

Muy similar al ejemplo anterior, pero sustituimos $* por simplemente * que equivale a todos los ficheros del directorio activo.

for i in *
do
instrucciones
done
              

Leer un fichero de texto línea a línea

Es muy habitual tener que procesar todas las línea de un fichero de texto para realizar diferentes operaciones. Vemos una primera forma:

while read LINEA
do
instucciones por línea
done <fichero
              

En este caso estamos redirigiendo la entrada estándar de la orden read, que es el teclado, por un fichero. Al igual que en el caso del teclado, la lectura se realizará hasta que se encuentre un salto de línea. Observamos como la redirección se realiza tras el final de la sentencia while.

Otra forma posible para hacer esto mismo sería:

cat fichero|while read LINEA
do
instrucciones por línea
done
              

Este método difiere ligeramente del anterior, ya que al utilizar una tubería creamos una nueva shell con lo cual puede ocurrir que no se conserven ciertos valores de las variables de shell.

Cambiar una secuencia de espacios por un separador de campos

La salida de ciertas órdenes y ciertos ficheros separan los datos por espacios en blanco. Por ejemplo las órdenes ps o ls -la, o ifconfig.

Si queremos utilizar parte de los datos de las salidas de estas órdenes tendremos que contar las columnas en las que aparece cada dato y cortarlos con cut usando la opción -c. Pero otra opción sería sustituir toda una serie de espacios en blanco por un separador, por ejemplo ":" o ";".

Por ejemplo vamos a ver como sustituir los espacios de la orden ifconfig por ";".

La salida normal sería:

$ /sbin/ifconfig
eth0      Link encap:Ethernet  HWaddr 00:90:F5:08:37:E4
          inet addr:192.168.1.5  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:5103 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          Interrupt:10 Base address:0x3200
              
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1726 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1726 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
              

Ahora usamos sed para sustituir cualquier secuencia de espacios en blanco ([ ][ ]*) por un separador ";":

$ /sbin/ifconfig |sed "s/[ ][ ]*/;/g"
eth0;Link;encap:Ethernet;HWaddr;00:90:F5:08:37:E4;
;inet;addr:192.168.1.5;Bcast:192.168.1.255;Mask:255.255.255.0
;UP;BROADCAST;MULTICAST;MTU:1500;Metric:1
;RX;packets:0;errors:0;dropped:0;overruns:0;frame:0
;TX;packets:5241;errors:0;dropped:0;overruns:0;carrier:0
;collisions:0;txqueuelen:100;
;Interrupt:10;Base;address:0x3200;
              
lo;Link;encap:Local;Loopback;
;inet;addr:127.0.0.1;Mask:255.0.0.0
;UP;LOOPBACK;RUNNING;MTU:16436;Metric:1
;RX;packets:1773;errors:0;dropped:0;overruns:0;frame:0
;TX;packets:1773;errors:0;dropped:0;overruns:0;carrier:0
;collisions:0;txqueuelen:0;
              

Ahora podríamos cortar de forma exacta el campo que nos interese, por ejemplo:

$ /sbin/ifconfig | sed "s/[ ][ ]*/:/g" | grep inet | cut -f4 -d:
192.168.1.5
127.0.0.1
              

Vemos paso a paso la anterior orden compuesta:

Primero ejecutamos la orden ifconfig

Sustituimos los espacios en blanco por ":"

Buscamos la línea que contenga la palabra inet

Cortamos el campo 4 usando ":" como separador.