La mayoría del trabajo de línea de comandos se realiza sobre archivos. En esta sección discutimos cómo mirar y filtrar el contenido de archivos, tomar la información necesaria de los archivos utilizando un único comando, y clasificar con facilidad el contenido de un archivo.
Estos comandos tienen casi la misma sintaxis: nombre_del_comando [opciones] [archivo(s)], y se pueden usar en una tubería. Todos se utilizan para imprimir parte de un archivo de acuerdo con ciertos criterios.
El utilitario cat concatena archivos imprimiendo los resultados en la salida estándar, la cual es por lo general la pantalla de su computadora. Este es uno de los comandos más ampliamente utilizados. Por ejemplo, puede usar:
# cat /var/log/mail/info
para imprimir, por ejemplo, el
contenido del archivo de registro de un demonio de correo a la
salida estándar[25]. El comando
cat tiene una opción muy útil (-n
) que le
permite escribir los números de las líneas.
Algunos archivos, como los
archivos de registro de los demonios (si es que están corriendo)
por lo general tienen un tamaño enorme[26] y no es muy útil
imprimirlos por completo en la pantalla. Por lo general Usted sólo
necesita ver algunas líneas del archivo. Puede utilizar el comando
tail para esto. El comando siguiente imprimirá, de manera
predeterminada, las últimas 10 líneas del archivo
/var/log/mail/info
:
# tail /var/log/mail/info
Por lo general los
archivos de registro varían dinámicamente debido a que el demonio
asociado a dicho registro constantemente añade acciones y eventos
al archivo de registro. Si desea mirar interactivamente los
cambios al archivo de registro puede aprovechar la opción
-f
:
# tail -f /var/log/mail/info
En este caso, todos
los cambios en el archivo /var/log/mail/info
se imprimirán de inmediato en la pantalla. Utilizar el comando
tail con la opción -f
es muy útil cuando
desea saber cómo funciona su sistema. Por ejemplo, mirando a
través del archivo de registro
/var/log/messages
, puede estar al tanto con
los mensajes del sistema y varios demonios.
Si utiliza a tail con más
de un archivo, se imprimirá el nombre del archivo en una línea por
separado antes de imprimir el contenido del mismo. Esto también
funciona con la opción -f
y es una valiosa
adición para ver como interactúan las diferentes partes del
sistema.
Puede usar la opción
-n
para mostrar las últimas N líneas de un
archivo. Por ejemplo, para mostrar las últimas 2 líneas debería
ingresar:
# tail -n2 /var/log/mail/info
Al igual que para los
otros comandos, puede usar opciones diferentes a la vez. Por
ejemplo, usando tanto la opción -n2
como la
opción -f
a la vez, comienza con las últimas dos
líneas del archivo y sigue viendo las líneas nuevas a medida que
se van escribiendo en el archivo de registro.
El comando head es
similar a tail, pero imprime las primeras líneas de un
archivo. El siguiente comando imprimirá, de manera predeterminada,
las primeras 10 líneas del archivo
/var/log/mail/info
:
# head /var/log/mail/info
Al igual que con
tail Usted puede usar la opción -n
para
especificar la cantidad de líneas a imprimir. Por ejemplo, para
imprimir las primeras 2 ingrese:
# head -n2 /var/log/mail/info
También puede usar estos comandos juntos. Por ejemplo, si desea mostrar sólo las líneas 9 y 10, puede usar un comando donde primero el comando head va a seleccionar las primeras 10 líneas de un archivo y pasarlas a través de una tubería al comando tail.
# head /var/log/mail/info | tail -n2
La última parte seleccionará entonces las últimas 2 líneas y las imprimirá en la pantalla. De la misma manera, puede seleccionar la línea número 20, comenzando desde el final del archivo:
# tail -n20 /var/log/mail/info | head -n1
En este ejemplo, le decimos a tail que seleccione las últimas 20 líneas y las pase por una tubería a head. Luego, el comando head imprime la primer línea de los datos obtenidos.
Supongamos que deseamos
imprimir el resultado del último ejemplo en la pantalla y
guardarlo en el archivo resultados.txt
. El
utilitario tee nos puede ayudar. La sintaxis del mismo
es:
tee [opciones] [archivo]
Ahora podemos cambiar el comando anterior de esta manera:
# tail -n20 /var/log/mail/info | head -n1 | tee resultados.txt
Tomemos otro ejemplo.
Deseamos seleccionar las últimas 20 líneas, guardarlas en el
archivo resultados.txt
, pero imprimir en
pantalla sólo la primera de las 20 líneas seleccionadas. Entonces,
deberíamos teclear:
# tail -n20 /var/log/mail/info | tee resultados.txt | head -n1
El comando tee
posee una opción útil (-a
) que le permite añadir
datos a un archivo existente.
En la próxima sección veremos cómo podemos utilizar el comando grep como filtro para separar los mensajes de Postfix de aquellos mensajes que provienen de otros servicios.
Ni el acrónimo (“General Regular Expression Parser”, Analizador General de Expresiones Regulares), ni el nombre son muy intuitivos, pero su uso es simple. grep busca el patrón pasado como argumento en uno o más archivos. La sintaxis es:
grep [opciones] <patrón> [uno o más archivos]
Si se mencionan varios archivos, los
nombres de los mismos precederán a cada línea que muestra los
resultados que se corresponden con el criterio de búsqueda. Use la
opción -h
para ocultar estos nombres; use la
opción -l
para obtener sólo los nombres de
archivo en los cuales se cumple la condición de búsqueda. El
patrón es una expresión regular, aunque generalmente consiste en
una palabra simple. Las opciones usadas más frecuentemente son las
siguientes:
-i
: realizar una búsqueda
que ignore la capitalización. (es decir, que ignore la diferencia
entre las mayúsculas y las minúsculas);
-v
: búsqueda
inversa. Mostrar las líneas que no se
corresponden con el patrón;
-n
: mostrar, para
cada línea encontrada, el número de línea;
-w
: le dice a
grep que el patrón debe corresponderse con una palabra
completa, es decir debe aparecer tal cual y no como parte de otra
palabra.
Volvamos entonces a
analizar el archivo de registro del demonio de correo. Deseamos
encontrar todas las líneas en el archivo
/var/log/mail/info
que contengan el patrón
“postfix”. Entonces tecleamos este comando:
# grep postfix /var/log/mail/info
Si deseamos encontrar
todas las líneas que NO contienen el patrón
“postfix”, deberíamos usar la opción
-v
:
# grep -v postfix /var/log/mail/info
El comando grep se puede utilizar en una tubería.
Supongamos que deseamos
encontrar todos los mensajes acerca de correos enviados
satisfactoriamente. En este caso tenemos que filtrar todas las
líneas que fueron añadidas al archivo de registro por el demonio
de correo (contiene el patrón postfix
) y deben
contener un mensaje acerca del envío satisfactorio
(status=sent
)[27]:
# grep postfix /var/log/mail/info | grep status=sent
En este caso se
utiliza a grep dos veces. Esto está permitido, pero no es
muy elegante. Podemos obtener el mismo resultado utilizando el
utilitario fgrep. En realidad fgrep es una forma más
fácil de invocar a grep -F. Primero, debemos
crear un archivo que contiene los patrones escritos en una
columna. Se puede crear tal archivo de la manera siguiente (usamos
el nombre patrones.txt
):
# echo -e 'status=sent\npostfix' > ./patrones.txt
Verifique los
resultados con el programa cat. \n
es un
patrón especial que significa “línea nueva”.
Luego llamamos al
comando siguiente donde usamos el archivo
patrones.txt
con una lista de patrones y el
utilitario fgrep en vez de la “doble llamada”
a grep:
# fgrep -f ./patrones.txt /var/log/mail/info
El archivo
./patrones.txt
puede tener tantos patrones
como Usted desee. Por ejemplo, para seleccionar los mensajes
acerca de los envíos satisfactorios de correo a
peter@mandriva.com
, será suficiente añadir
esta dirección electrónica en nuestro archivo
./patrones.txt
ejecutando el comando
siguiente:
# echo 'peter@mandriva.com' >> ./patrones.txt
Está claro que puede combinar
grep con tail y head. Si deseamos encontrar
los mensajes sobre los últimos correos enviados a
peter@mandriva.com
, excepto el último,
tecleamos:
# fgrep -f ./patrones.txt /var/log/mail/info | tail -n2 | head -n1
Aquí aplicamos el filtro descrito arriba y colocamos el resultado en una tubería para los comandos tail y head. Los mismos seleccionan los últimos valores de los datos, excepto el último.
Con grep estamos limitados con patrones y datos fijos ¿Cómo podríamos encontrar todos los correos electrónicos enviados a cada empleado de la “Empresa ABC”? Listar todos los correos electrónicos de los mismos no sería una tarea fácil ya que alguno podría escaparse o se debería buscar a mano en el archivo de registro.
Al igual que con fgrep, grep tiene un atajo al comando grep -E: egrep. El mismo toma como parámetro expresiones regulares en vez de patrones, brindando así una interfaz más potente para tratar texto.
Además de lo que mencionamos en Sección 3, “Patrones de englobamiento del shell” cuando hablamos de patrones de englobamiento, a continuación tiene algunas expresiones regulares más:
[:alnum:]
,
[:alpha:]
y [:digit:]
se
pueden usar en vez de definir las clases de caracteres y
representan, respectivamente, todas las letras más todos los
dígitos, todas las letras (mayúsculas y minúsculas), y todos los
dígitos. Es más: dichas expresiones incluyen a los caracteres
internacionales y respetan la localización del sistema.
[:print:]
representa a todos los caracteres que se pueden imprimir en la
pantalla.
[:lower:]
y
[:upper:]
representan a todas las letras
minúsculas y a todas las mayúsculas.
Hay más clases disponibles y puede verlas a todas en egrep(1). Las arriba mencionadas con las usadas con más frecuencia.
Una expresión regular puede estar seguida por uno o más operadores de repetición:
Si pone una expresión regular
entre paréntesis después la puede recuperar. Digamos que
especificó la expresión [:alpha:]+
. Puede que
represente una palabra. Si desea detectar palabras que ocurren
dos veces puede poner la expresión entre paréntesis y volver a
usarla con \1
si este es el primer
grupo. Puede tener hasta 9 de estas
“memorias”.
$ echo -e "abc def\nabc abc def\nabc1 abc1\nabcdef\nabcdabcd\nabcdef abcef" > archivo_prueba $ egrep "([[:alpha:]]+) \1" archivo_prueba abc abc def $
La única línea que se devuelve es aquella que coincidió exclusivamente con dos grupos de letras separados por un espacio. Ningún otro grupo coincidió con la expresión regular.
También puede usar el caracter
|
para hacer coincidir la expresión a la
izquierda del |
o la expresión a la derecha del
mismo. Es un operador que une dichas expresiones. Usando el mismo
archivo archivo_prueba
creado antes, puede
intentar buscar sólo expresiones que contienen palabras dobles o
contienen palabras dobles con números:
$ egrep "([[:alpha:]]+) \1|([[:alpha:][:digit:]]+) \2" archivo_prueba abc abc def abc1 abc1 $
Note que para el segundo grupo que
usa paréntesis se tuvo que utilizar \2
, de lo
contrario no hubiera coincidido con lo que se deseaba. Una
expresión más eficiente sería, en este caso en particular:
$ egrep "([[:alnum:]]+) \1" archivo_prueba abc abc def abc1 abc1 $
Finalmente para hacer
coincidir ciertos caracteres tiene que “escaparlos”,
precediéndolos con una contrabarra. Dichos caracteres son:
?
, +
, {
,
|
, (
, )
y
por supuesto \
. Para hacer coincidir con ellos
se debe escribir: \?
, \+
,
\{
, \|
,
\(
, \)
y
\\
.
Este truco simple lo puede ayudar a que evite teclear palabras repetidas en “su su” texto.
Las expresiones regulares en todas las herramientas deberían seguir estas reglas, o reglas muy similares. Dedicar algo de tiempo a entender estas reglas lo ayudará un montón con las otras herramientas tales como sed. sed le permite, entre otras cosas, manipular texto, cambiándolo usando expresiones regulares como reglas.
El comando wc (Word Count, Cuenta de palabras) se usa para calcular la cantidad de líneas, palabras y caracteres en archivos. También es útil para computar la longitud de la línea más larga. Su sintaxis es:
wc [opciones] [archivo(s)]
Las siguientes opciones son útiles:
El comando wc imprime la cantidad de líneas nuevas, palabras y caracteres de manera predeterminada. Aquí tiene algunos ejemplos de uso:
Si deseamos encontrar la cantidad de usuarios en nuestro sistema, podemos teclear:
$wc -l /etc/passwd
Si deseamos saber la cantidad de CPUs en nuestro sistema, tecleamos:
$grep "model name" /proc/cpuinfo | wc -l
En la sección anterior
obtuvimos una lista de mensajes acerca de los correos enviados
satisfactoriamente a las direcciones listadas en nuestro archivo
./patrones.txt
. Si deseamos saber la cantidad
de dichos mensajes, podemos enviar los resultados de
nuestro filtro por una tubería al comando wc:
# fgrep -f ./patrones.txt /var/log/mail/info | wc -l
Aquí tiene la sintaxis de este poderoso utilitario de clasificación[28]:
sort [opciones] [archivo(s)]
Consideremos clasificar parte de el
archivo /etc/passwd
. Como puede ver este
archivo no está clasificado:
$ cat /etc/passwd
Deseamos clasificarlo por el
campo login
. Entonces tecleamos:
$ sort /etc/passwd
El comando sort
clasifica datos de manera ascendente comenzando por el primer
campo (en nuestro caso, el campo login
) de
manera predeterminada. Para clasificar los datos de manera
descendente, use la opción -r
:
$ sort -r /etc/passwd
Cada usuario tiene su propio
UID
escrito en el archivo
/etc/passwd
. Clasifiquemos un archivo de
manera ascendente con el campo UID
:
$ sort /etc/passwd -t":" -k3 -n
Aquí utilizamos las siguientes opciones de sort:
Se puede hacer lo mismo de manera inversa:
$ sort /etc/passwd -t":" -k3 -n -r
Note que sort tiene dos opciones importantes:
Finalmente, si deseamos
encontrar el usuario con el mayor UID
podemos
usar el comando siguiente:
$ sort /etc/passwd -t":" -k3 -n | tail -n1
donde clasificamos al archivo
/etc/passwd
de manera ascendente de acuerdo a
la columna UID
, y enviamos el resultado por
medio de una tubería al comando tail que imprime el primer
valor de la lista clasificada.
[25] Algunos ejemplos de esta sección están basados en
trabajo real con archivos de registro de algunos servidores
(servicios, demonios). Debe asegurarse que
syslogd (permite el registro de los
demonios) y el demonio correspondiente (en este ejemplo
Postfix) estén activos, y que Usted trabaja como
root
. Por supuesto, siempre puede aplicar nuestros
ejemplos a otros archivos.
[26] Por ejemplo, el archivo
/var/log/mail/info
contiene información
acerca de todos los correos enviados, mensajes acerca de la
recuperación de correo por parte de los usuarios con el protocolo
POP, etc.
[27] Aunque es posible filtrar sólo por el patrón de estado, por favor siga el ejemplo ya que la finalidad es mostrarle un comando nuevo.
[28] Discutimos a sort brevemente aquí. Se podrían escribir libros completos acerca de sus características.