Algo de Linux: marzo 2008

lunes, 31 de marzo de 2008

El shell de linux: Manipulación de cadenas

En bash podemos realizar operaciones de manipulación de cadenas, como por ejemplo:
  • Obtener la longitud de una cadena.
  • Buscar caracteres dentro de una cadena.
  • Extraer una subcadena de una cadena.
Obtener la longitud de una cadena de caracteres.-
Podemos obtener la longitud de una cadena de tres formas:
  • ${#cadena}
  • expr length $cadena
  • expr "$cadena" : '.*'
Ejemplos:
$ micadena="Bienvenido al mundo de Linux"
$ echo "La longitud de la cadena es: `expr length $micadena`"
$ echo "La longitud de la cadena obtenida de otro modo: `${#micadena}`"
Buscar una cadena dentro de otra cadena de caracteres.-
Podemos averiguar cual es la posición de una cadena dentro de otra, utilizando las siguiente expresión:

expr index cadena_donde_buscar cadena_a_buscar

Devuelve la posición donde encuentra los caracteres a buscar dentro de la cadena, si no, devuelve un 0.

Ejemplo:
micadena="Bienvenido al mundo de Linux"
cadenaabuscar="Linux"
echo “La cadena $buscar se encuentra en la pos `expr index $micadena $cadenaabuscar`”
Como podemos ver, index busca una cadena, pero si lo que queremos utilizar como patrón de búsqueda es una expresión regular, usaremos:

expr match cadena_donde_buscar patrón_caracteres_buscar

Ejemplo:
cadena="342 ovejas en el redil"
numero=`expr match $cadena [0-9]*`
echo "El número de dígitos al comienzo de la cadena $cadena es: $numero"

Extraer una subcadena de una cadena de caracteres.-

Si queremos extraer una subcadena de una cadena de caracteres, utilizamos la siguiente expresión:

expr substr cadena posición n_caracteres

Para extraer una subcadena de una cadena indicamos la cadena, la posición y longitud a extraer.

Ejemplo:
$nif="70245678D"
echo “El DNI de $nif es `expr substr $nif 1 8`”
echo "La letra del $nif es `expr substr $nif 9 1`"

El shell de linux: Comando let

El comando let nos permite trabajar fácilmente con variables numéricas en scripts.
Por ejemplo: Supongamos que queremos multiplicar por 2 el valor de una variable y almacenar el resultado en otra:

$ simple=4
$ let doble=simple*2

Si después de ejecutar estas dos instrucciones en un terminal, hacemos un:

$ echo $doble


Veremos que la variable doble vale 8.

Un ejemplo completo: Hacer un bucle while que incremente el valor de una variable CONTADOR y vaya mostrando los valores que toma dicha variable:

#!/bin/bash


CONTADOR=0
MAX=20

while [ $CONTADOR -lt $MAX ]; do
let CONTADOR=CONTADOR+1
echo El contador es $CONTADOR

done

jueves, 27 de marzo de 2008

Intefaz web de administración de ejabberd

Tengo montado un servidor de mensajería interna para profesores en el centro, mediante ejabberd y gaim en los clientes. Me es muy útil para comunicar algo a alguien concreto en un momento dado, y también para que ellos me informen de cuestiones urgentes.

Como no creo usuarios en ejabberd con demasiada frecuencia, se me olvidan los detalles de acceso al interfaz web de administración de este servidor de mensajería, así que lo pongo aquí, y cuando se me olvide, ya sé dónde buscar...

Para acceder al interfaz de administración web, abrimos el navegador y escribimos la dirección IP de la máquina donde tenemos instalado ejabberd, indicando el puerto 5280 y /admin. Suponiendo que la dirección IP de mi servidor es 192.168.1.16, sería algo así:

http://192.168.1.16:5280/admin

Se nos abre una ventana en la que nos pide que introduzcamos el nombre de usuario y contraseña. Un detallito importante: No vale con escribir el nombre de usuario a secas. Es necesario especificar el nombre de dominio con el que hemos configurado el servidor. Es decir, si mi nombre de usuario es esteban y en el servidor jabber he configurado como nombre de dominio miempresa.ex, tendré que escribir como nombre de usuario:

esteban@miempresa.ex

miércoles, 19 de marzo de 2008

El shell de linux: Comando which

El comando which nos sirve para averiguar donde se encuentra instalado un determinado programa.

Por ejemplo, si ejecutamos:
$ which find

Nos devolverá:
/usr/bin/find

Ésto nos mostrará la primera aparición del programa buscado. Si queremos que nos muestre todas las ocurrencias que encuentre, utilizaremos el parámetro -a.

Así, si ejecutamos:
$ which -a find

Nos devolverá todas las ocurrencias que encuentre:
/usr/bin/find
/usr/bin/X11/find

Para realizar la búsqueda which localiza los ficheros ejecutables mediante el PATH.

Ésto puede sernos útil, por ejemplo, para comprobar si tenemos dos versiones de un mismo programa instalado en diferentes directorios.

El shell de linux: Comando find

Utilizamos este comando para buscar archivos dentro de una jerarquía de directorios. Pero, lo mejor de todo es que no sólo podemos buscar, sino que, además, podemos ejecutar acciones sobre los elementos localizados por el comando find.
Por otro lado, podemos realizar la búsqueda mediante varios criterios.
La sintaxis de este comando es:
find [ruta...] [expresión]
Veamos un ejemplo sencillo: Queremos buscar los archivos de imágenes con extensión .jpg en el directorio del usuario ambrosio:
$ find /home/ambrosio -name "*.jpg"

Otro ejemplo: Imaginemos que quiero listar los directorios que hay en el directorio actual:
$ find ./ -maxdepth 1 -type d

Ahora imaginemos que quiero listar los ficheros que se han modificado hoy en el directorio actual:
$ find ./ -mtime 0 -type f

Si quisieramos borrar todos los subdirectorios del directorio /var/backup que tengan una antigüedad mayor de 20 días:
$ find /var/backup -mtime +20 -type d -exec rm -f {} \;

Otro ejemplo: Queremos borrar todos los directorios del sistema que contengan la palabra sane:
# find / -name "*sane*" -type d -exec rm -fr {} \; 2>/dev/null

Si lo que queremos es borrar todos los ficheros del sistema que contengan la palabra sane, no tenemos más que cambiar el tipo en el comando anterior:
# find / -name "*sane*" -type f -exec rm -fr {} \; 2>/dev/null

Otro ejemplo: Imaginemos que queremos recopilar todos los ficheros mp3 que tenemos repartidos en diferentes directorios y moverlos a un único directorio:
# find / -name "*.mp3" -exec mv {} /compartido/musica/ \;

Imaginemos también que los usuarios de nuestro sistema descargan ficheros mp3 que almacenan en sus cuentas y terminan excediendo su cuota. Tan sólo tenemos que ejecutar el siguiente comando y borraremos todos los mp3 que haya en el home:
# find /home -name "*.mp3" -exec rm {} \;

Ahora supongamos que queremos borrar todos los archivos y directorios propiedad de un usuario del directorio tmp:
# find /tmp -user enavas -exec rm -fr {} \;

Como podéis ver, el comando find es tremendamente útil.

lunes, 17 de marzo de 2008

Equivalente a Hacha en linux

A veces, queremos partir un archivo en otros más pequeños con el fin de guardarlos por partes debido a su gran tamaño o queremos juntar las parte de un archivo que nos hemos descargado de internet.

En windows, se utiliza mucho el popular Hacha. Pues bien, en Linux también disponemos de un programa compatible con el famoso Hacha, aunque es bastante menos conocido: Se llama Hoz.

Hoz está disponible tanto para Windows como para Linux. En Ubuntu, por ejemplo, se encuentra en los repositorios, por lo que su instalación es de lo más sencilla.

# apt-get install hoz

Hoz es un programa que se utiliza desde la línea de comandos. Si queremos unir o partir archivos en modo gráfico, usaremos un gui disponible para hoz.
El paquete para instalarlo se llama hoz-gui.

# apt-get install hoz-gui

Una vez instalado, ya podremos partir y unir archivos utilizando el gui. Por cierto, el programa se llama ghoz. En cuanto a su uso, es muy sencillo.

lunes, 10 de marzo de 2008

Linux: Expresiones regulares

Una expresión regular es un patrón que nos permite buscar un texto formado por metacaracteres y caracteres ordinarios.

Los metacaracteres son ciertos caracteres con un significado específico dentro de una expresión regular. Estos caracteres tienen un significado que va más allá del símbolo que representan y tienen un comportamiento especial en una expresión regular.

Aquí tenéis una lista de metacaracteres que usamos en expresiones regulares:
  • . Significa cualquier caracter.
  • ^Indica el principio de una línea.
  • $ Indica el final de una línea.
  • * Indica cero o más repeticiones del caracter anterior.
  • + Indica una o más repeticiones del caracter anterior.
  • \< Indica el comienzo de una palabra.
  • \> Indica el final de una palabra.
  • \ Caracter de escape. Da significado literal a un metacaracter.
  • [ ] Uno cualquiera de los caracteres entre los corchetes. Ej: [A-Z] (desde A hasta Z).
  • [^ ] Cualquier caracter distinto de los que figuran entre corchetes: Ej: [^A-Z].
  • { } Nos permiten indicar el número de repeticiones del patrón anterior que deben darse.
  • | Nos permite indicar caracteres alternativos: Ej: (^|[?&])
  • ( ) Nos permiten agrupar patrones. Ej: ([0-9A-F]+:)+
Ojo. En las expresiones regulares se distingue entre mayúsculas y minúsculas.

Si queremos representar un caracter entre la a y la z, lo haremos de la siguiente manera: [a-z]
Dentro del conjunto, podemos especificar todos los caracteres que queramos. Por ejemplo: [a-zA-Z] representaría los caracteres alfabéticos en minúsculas y mayúsculas. Eso sí. El conjunto representa a un sólo caracter.
Si lo que queremos es representar identificar un número o una letra, podríamos hacerlo así:
[a-zA-Z0-9]

Los conjuntos pueden representarse, nombrando todos y cada uno de los elementos, o el intervalo. Ej: [0-9] representa lo mismo que [0123456789].

Si queremos representar un número que se compone de cero o más dígitos: [0-9]*

Y si queremos representar un número que se compone de uno o más dígitos: [0-9]+

Si ahora queremos representar cualquier caracter menos los dígitos: [^0-9]

Ahora, imaginemos que queremos representar un número de 5 dígitos: [0-9]{5}

Y si quisieramos representar una palabra que tiene entre dos y cuatro caracteres: [a-zA-Z]{2,4}

Dentro de los conjuntos de caracteres individuales, se reconocen las siguientes categorías:

[:alnum:] alfanuméricos
[:alpha:] alfabéticos
[:cntrl:] de control
[:digit:] dígitos
[:graph:] gráficos
[:lower:] minúsculas
[:print:] imprimibles
[:punct:] de puntuación
[:space:] espacios
[:upper:] mayúsculas
[:xdigit:] dígitos hexadecimales

Vamos a ver algunos ejemplos de expresiones regulares:

# grep '^La' fichero

El comando anterior nos devuelve todas las líneas del fichero que comienzan por La.

# grep '^ *La' fichero
El comando anterior nos devuelve todas las líneas del fichero que comienzan por cualquier número de espacios seguido de La.

# grep '^\..*' fichero
El comando anterior nos devuelve todas las líneas del fichero que comienzan por punto y tienen cualquier número de caracteres.

# ls -la | grep ' \..*'
El comando anterior nos devuelve la lista de ficheros que comienzan por un espacio seguido de un punto y cualquier número de caracteres, es decir, la lista de ficheros ocultos.

# ls -l | grep '^d'
El comando anterior nos devuelve la lista de ficheros que comienzan por d, es decir, la lista de directorios.

viernes, 7 de marzo de 2008

Asociar tipos de archivo a aplicaciones en GNOME

En GNOME podemos asociar un determinado tipo de archivo para que se abra con una aplicación determinada. Esta asociación podemos hacerla a nivel de usuarios o a nivel de máquinas.


Yo he preferido configurar la asociación en cada máquina para que por defecto se establezca la asociación que yo he elegido, pero que después el usuario puede cambiar, dado que cualquier asociacion hecha de forma particular por un usuario tendra prioridad sobre la general.

Esta asociacion viene especificada de forma general en el archivo /etc/gnome-vfs-2.0/defaults.list

Cada entrada está formada por un par:

mime-type=lanzador.desktop

donde mime-type será el tipo mime concreto que queremos asociar con la aplicación. Y lanzador.desktop debe ser uno de los lanzadores que hay en el directorio /usr/share/applications.

Por ejemplo:

application/rtf=abiword.desktop=ooo-writer.desktop

martes, 4 de marzo de 2008

El shell de linux: Awk

Awk busca ciertos patrones en la entrada, y la procesa de la manera especificada. Awk tiene una gran funcionalidad, pero esta mayor funcionalidad tiene su coste reflejado en una mayor complejidad del lenguaje.

awk dispone de un lenguaje completo, sintácticamente similar a C que tiene una gran potencia a la hora de reconocer patrones en la entrada, ya que permite especificar combinaciones de expresiones regulares.

Además, no es necesario procesar la entrada línea a línea. Awk permite escoger el carácter que indica el fin de un registro y procesar la entrada de registro en registro (En el lenguaje awk, un ‘registro’ es el equivalente a una ‘línea’).
Awk separa automáticamente cada registro en campos que pueden utilizarse individualmente.

Por defecto, un registro es una línea del fichero, lo que significa que el separador de registros es ‘\n’.

Por defecto, un campo es todo aquello que esté separado por espacios en blanco, es decir, una palabra. El separador de campos por defecto es '[ \t]' (espacio y tabulador).

Una posible sintaxis de awk sería:
awk [fichero_entrada]
Un programa de awk es una secuencia de sentencias patrón-acción, con un formato determinado, en el que las acciones se ejecutarán si en el registro actual se cumple el patrón.
El formato es el siguiente:
patrón {accion}
Suele ser necesario encerrar los programas de awk entre comillas, para evitar que el shell las interprete como caracteres especiales.

Hay que tener en cuenta dos cosas:
  • Si no hay patrón, las acciones se ejecutan en todos los registros.
  • Si no hay acciones, lo que se hace es ejecutar la acción por defecto, que es copiar el registro en la salida estándar.
Veamos un par de ejemplos o tres de uso de awk:

* Mostramos el nombre de usuario de todos los usuarios logueados en la máquina:
who|awk '{print $1}'
* Borramos todas las líneas vacías de un fichero:
awk '!/^$/ {}' fichero
* Mostramos el nombre de usuario y el intérprete que usa:
awk 'BEGIN {FS=":"}; {print $1,$NF | "sort"}' /etc/passwd
* Mostramos el nombre completo del usuario y su login:
awk 'BEGIN {FS=":"}; {print $1,$5 | "sort"}' /etc/passwd

Variables
Como ya hemos dicho, awk dispone de un lenguaje completo, y, como cualquier otro lenguaje, dispone de variables. Las variables pueden ser de dos tipos:

  • Variables predefinidas.
  • Variables definidas por el usuario.
Veamos cuales son las variables predefinidas:
  • FS (Field separator): Permite indicar a awk cuál es el caracter que separa los campos. Por defecto es el espacio. La forma de indicar a awk el caracter de separación de campos es la siguiente: FS = “caracter”. Por ejemplo: FS = ",". Si hacemos FS = "", estamos indicando a awk que cada carácter es un campo.
  • NF (Number of fields): Contiene el número total de campos que contiene el registro que se está leyendo en cada momento.
  • RS (Record separator): Contiene el carácter que indica a awk en qué punto del archivo acaba un registro y empieza el siguiente. Por defecto es el caracter “\n”.
  • NR (Number of record): Contiene el número de orden del registro que se está procesando en cada momento.
  • OFS (Output FS): La instrucción print inserta en la salida un carácter de separación cada vez que aparece una coma en el código. Mediante OFS, podemos indicar a awk que separe los campos mediante el separador que le indiquemos. Por ejemplo: OFS = ";"

En cuanto a las variables definidas por el usuario, se crean directamente al hacer referencia a ellas en expresiones.

Las variables pueden ser:

  • Escalares: Almacenan un solo valor.
  • Vectoriales: Como vectores o arrays. En awk, se pueden crear arrays asociativos, dado que el lenguaje nos permite usar una cadena como índice del array. Para referirnos a un elemento dentro de un array, lo haremos: nombre[ subíndice ].

Campos de entrada
En Awk se considera cada registro del archivo de entrada como una sucesión de campos delimitados por un carácter dado. Este carácter es, por defecto, el espacio.
En cualquier caso, podemos indicar a awk que considere otro carácter como separador de campos mediante la opción FS, tal y como podemos ver en ejemplos anteriores.

Cada uno de estos campos se numera de forma correlativa, según su posición en la línea (o registro), de la siguiente manera: $1, $2, $3, ... Además, también podemos referirnos a la línea entera con $0.

Por otra parte, se puede forzar a procesar una línea carácter a carácter, dejando la variable “separador de campos” FS sin contenido. Si hacemos ésto, en $1 se tendrá el primer carácter de la línea, en $2 el segundo, etc.

El otro día me encontré con el siguiente ejercicio:

Hacer un script que visualice la lista de usuarios que se encuentran conectados en el sistema, mediante el siguiente formato: nº orden -- nombre usuario, totalizando el nº de usuarios. Ejemplo:

1 -- root
2 -- df01
3 -- df02


Utilizando awk, la solución es tan sencilla como la siguiente:
#/bin/bash
who -u|awk 'BEGIN { i=0 } { i+=1; print i,"-",$1 } END { print "Total usuarios " i }'

Estructura básica de un programa con awk
Para entender fácilmente la estructura de un programa con awk, podemos fijarnos en el ejemplo anterior, en el que tenemos tres bloques:
  • BEGIN { i=0 }
  • { i+=1; print i,"-",$1 }
  • END { print "Total usuarios " i }
El primero, se ejecuta al inicio. En este caso, hemos utilizado el bloque BEGIN para inicializar la variable i con valor 0.
El segundo bloque se ejecuta para cada patrón (o registro, como queramos llamarlo). En este caso, incrementa el valor de i, y lo muestra por pantalla seguido de un guión y el campo nº 1 (que en este ejemplo es el login del usuario) Como no hemos indicado ningún separador de campo, se toma por defecto el espacio.
El tercer bloque se ejecuta al final. ¿Y qué hace el bloque en el ejemplo? Imprimir el número total de usuarios.

Awk puede servirnos muy bien para procesar ficheros de texto, extraídos de bases de datos, en los que tenemos registros con campos de datos.

Como ya hemos dicho, awk dispone de un lenguaje completo, con sentencias, condicionales, bucles, estructuras ... Una sentencia que puede sernos de utilidad en el procesamiento de ficheros, es el if. Veamos un ejemplo usando esta sentencia:

awk '{ if (x % 2 == 0) print "x is even"; else print "x is odd" }'

lunes, 3 de marzo de 2008

El shell de linux: Comando diff

El comando diff nos permite comparar dos ficheros linea a linea y nos informa de las diferencias entre ambos ficheros. Diff tiene muchas opciones. Las que más uso son -w, -q, -y.

La sintaxis del comando es la siguiente:
diff [opciones] [fichero1] [fichero2]
Si queremos comparar dos ficheros, ignorando los espacios en blanco, utilizaremos el parámetro -w:
diff -w fichero1 fichero2
Si lo que queremos es que no nos muestre las diferencias, sino que tan sólo nos informe de si son diferentes o no:
diff -q fichero1 fichero2
Si queremos que nos muestre la salida con las diferencias marcadas a dos columnas:
diff -y fichero1 fichero2
Como en muchos otros comandos, también podemos utilizar la opción -i, que ignora la diferencia entre mayúsculas y minúsculas.

El shell de linux: Comando date

date es otro de los comandos que utilizamos en ocasiones en scripts, como por ejemplo, cuando creamos un script que debe hacer copia de seguridad diaria. El nombre de las carpetas donde se almacena la copia de cada día se crea usando el comando date.

date presenta la fecha y la hora del sistema, datos que sólo puede modicar el usuario root y tiene que seguir el siguiente formato: MM DD HH MM [AA][ss]

Si utilizamos el comando date a secas, se nos mostrará la fecha y hora de la siguiente manera: día de la semana, mes, día, hora, zona horaria, año. Por ejemplo:
lun mar 3 12:51:22 CET 2008
Pero, normalmente en los scripts sólo utilizo el año, mes y día.

Para ver la fecha mediante otro formato, podemos hacerlo utilizando la siguiente sintaxis del comando:
date +formato

Opciones de formato de hora:
  • H : presenta la hora en el formato de 00 a 23.
  • k : presenta la hora de 0 a 23.
  • M : presenta los minutos de 00 a 59.
  • p : añadir AM o PM.
  • l : presenta la hora de 1 a 12.
  • r : presenta horas minutos segundos [A/P]o[A/M].
  • T : presenta horas minutos segundos.
  • a : presenta el día de la semana abreviado.
  • A : presenta el día de la semana completo.
  • b : presenta el mes abreviado.
  • B : presenta el mes completo.
Opciones de formato de fecha:
  • D : presenta meses días años.
  • d : presenta día.
  • m : presenta mes.
  • y : presenta año con el formato 01.
  • Y : presenta año con el formato 2001.
  • j : nos presenta el número de día juliano.
Ejemplo práctico:
nombrefichero=`date +"backup%Y%m%d"`
De este modo, estoy creando un nombre de fichero que tendrá la siguiente forma, por ejemplo: backup20080303

El shell de linux: Comando sed

Este comando también lo usamos mucho, porque nos permite, de una forma cómoda, borrar líneas, registros o sustituir cadenas de caracteres dentro de las líneas.

Para borrar una línea hacemos lo siguiente:

    sed 'nº_de_línead' fichero

Podemos indicar un número de línea concreto. Por ejemplo:

    sed '1d' fichero

Podemos indicar un intervalo de líneas a borrar. Por ejemplo:

    sed '3,5d' fichero

También podemos indicar que queremos borrar desde una determinada línea en adelante:

    sed '3,$d' fichero

Otro ejemplo útil es borrar las líneas en blanco de un fichero:

    sed '/^$/d' fichero

A la hora de borrar, también podemos especificar una cadena, de tal forma que el comando borrará todas las líneas que contengan esa cadena. Ejemplo:

    cat fichero | sed '/^[ ]*$/d' > ficherodestino

Lo anterior borrará todas las líneas en blanco de fichero.

Otro de los usos interesantes es borrar los espacios al comienzo de cada línea:

    sed 's/^ *//g' fichero

O borrar los espacios al final de cada línea:

    sed 's/ *$//g' fichero

Otro de los usos más interesantes de sed es sustituir cadenas. Podemos sustituir una cadena por otra de la siguiente manera:

    sed 's/cadena1/cadena2/' fichero

Al ejecutar el comando anterior, se sustituye la primera cadena que encuentra por la segunda. Pero, si lo que queremos es sustituir todas las cadenas que encuentre, en cada una de las líneas, añadimos el parámetro g:

    sed 's/cadena1/cadena2/g' fichero

Por otra parte, también podemos hacer que sustituya la cadena1 por la cadena2 en un número de línea concreto:

    sed '5 s/USUARIO/usuario/g' fichero

Con cadenas de texto normales la cosa es sencilla, pero al que más y al que menos le resulta complicado cuando lo que hay que sustituir son caracteres especiales como el tabulador: \t o el caracter de nueva línea: \n. Pero veamos como tampoco es complicado: Imaginemos que tenemos un fichero con campos en los que el separador es el tabulador y queremos sustuir este caracter separador por otro caracter separador, como por ejemplo el punto y coma (;). Lo haremos de la siguiente manera:

    sed 's/\t/;/g' fichero

El shell de linux: Comando tr

tr es un filtro que nos permite cambiar una determinada información de un archivo por otra.
Cambia cada uno de los caracteres especificados en el conjunto inicial por los caracteres especificados en el conjunto final.
El fichero de origen o fichero destino lo especificamos con los caracteres de redirección: < ó >.

Veamos un par de ejemplos o tres:
tr ':' ' ' < /etc/passwd > ficheropasswd
tr '[a-z]' '[A-Z]' <> listaalumnosmayusculas
tr ' ' '\n' <> lineasusuarios
tr -s " " <> prueba2

Parámetros útiles:
  • -s : Sustituye un conjunto de caracteres repetidos por uno sólo. Es muy útil cuando hay secuencias de caracteres que queremos borrar:
tr -s " " <> ficherodestino
  • -c : Hace que se traduzcan todos los caracteres que no se encuentren especificados en el primer parámetro. En el siguiente ejemplo se traduce por una ? todo lo que no sean letras o números.
tr -c '[a-z][A-Z][0-9]' ? <> ficherodestino
  • -d : Borra los caracteres que especifiquemos.
tr -d '[a-z][0-9]' ? <> ficherodestino
Otro ejemplo práctico que uso en ocasiones cuando quiero conseguir una lista, convirtiendo los caracteres de nueva línea en espacios:
  • tr '\n' ' ' < /etc/pkgsync/musthave > listaenunasolalinea

El shell de linux: Comando uniq

uniq es uno de los filtros que nos sirve para filtrar o eliminar las líneas repetidas con los que trabajamos bastante.

Podemos darle varios usos. El principal es eliminar lineas repetidas, tal y como hace el parámero -u del comando sort.
  • Para visualizar líneas no repetidas no tenemos que indicar ningún parámetro, aunque podemos pasarle el parámetro -u.
  • También podemos usar el parámetro -d para visualizar las líneas repetidas.
  • También podemos utilizarlo para contar líneas repetidas, pasándole el parámetro -c.

El shell de linux: Comando sort

sort es uno de los comandos que utilizamos mucho a la hora de realizar scripts.

Nos permite ordenar los registros o líneas de uno o más archivos.
La ordenación se puede hacer por el primer carácter, por el primer campo de la línea o por un campo distinto al primero en el caso de ficheros estructurados.

Podemos ordenar el contenido de un fichero de la siguiente manera:

sort fichero
Se realizaría la ordenación y el resultado se mostraría por pantalla. Así que, si lo que queremos es obtener el resultado de la ordenación en un fichero, haríamos:

sort fichero > ficheroordenado
Si lo que queremos es ordenar varios ficheros y añadir el resultado a otro, podemos indicar varios ficheros en la línea de entrada:

sort fichero1 fichero2 > fichero3
Y si lo que queremos es ordenar un fichero y dejar el resultado de la ordenación en el mismo fichero, podemos hacerlo con el parámetro -o (output):
sort -o f1 f1

Veamos una lista de los parámetros que pueden resultarnos más útiles a la hora de usar este comando:
  • -f : Este parámetro nos sirve para indicar que las mayúsculas y las minúsculas se van a tratar de forma diferente y que por tanto se va a seguir un ordenamiento alfabético.
  • -n : Este parámetro nos sirve para ordenar los campos numéricos por su valor numérico.
  • -r : Nos permite realizar una ordenación inversa, es decir, de mayor a menor.
  • +número : Este parámetro nos sirve para indicar la columna o campo por el que vamos hacer la ordenación. Esta sintaxis está en desuso y se va a eliminar. En su lugar se utilizará la siguiente sintaxis:
  • -k numero : De este modo especificaremos por qué columna o campo vamos a realizar la ordenación en las versiones más recientes de Linux.
  • --field-separator= separador. Normalmente, se usa como delimitador de campos el espacio en blanco. Podemos utilizar el parámetro --field-separator para indicar que vamos a usar otro delimitador de campo cualquiera. Ej: --field-separator=, La opción abreviada de --field-separator es -t.
  • -u : Nos permite suprimir todas las líneas repetidas después de realizar la ordenación.
Y algunos ejemplos con dichos parámetros:

Obtener un listado de los ficheros del directorio actual, ordenado por tamaño de archivo:
$ ls -l | sort +4n

Obtener un listado de los ficheros del directorio actual, ordenado de mayor a menor por tamaño de archivo:
$ ls -l | sort -r +4n

Obtener un listado de los ficheros del directorio actual, ordenado por nombre del archivo:
$ ls -l | sort +7
Ordenar un fichero eliminando las líneas repetidas:
$ sort -u fichero
Ordenar un fichero pen el que los campos están separados por comas, por el campo número 3:
$ sort -t, +3

Veamos un ejemplo en el que ordenemos usando la sintaxis actual para ordenar por columnas: Imaginemos que queremos ver un listado de usuarios del fichero /etc/passwd ordenado por uid:
$ cat /etc/passwd| sort -t":" -k3n

Con -k3 le indicamos a sort que queremos ordenar por la columna 3. Y, al añadir la opción -n le indicamos que ordene por orden numérico.

Y si quisiéramos realizar la ordenación de mayor a menor:
$ cat /etc/passwd| sort -t":" -k3nr

Un ejemplo que uso mucho, cuando quiero eliminar las líneas repetidas de un archivo y dejar el contenido en el mismo archivo:
$ sort -o fichero -u fichero