# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

Medir el tiempo que tarda un comando en ejecutarse


En Linux, gracias al comando “time“, podemos saber el tiempo que tarda en ejecutarse un determinado comando. La sintaxis es sencilla:

time comando

Por supuesto podemos asignar al comando unas cuantas opciones, como por ejemplo guardar las estadísticas en un fichero en vez de mostrarlas por pantalla, formatear la string que muestra el resultado del tiempo, etc. Para ello revisad la página man (man time) y veréis todas las posibilidades que ofrece.

Unos ejemplos:

Cambiar el propietario y grupo de la carpeta “test” y mostrar el tiempo que ha costado ejecutarlo:

$ time chown -R alex. test/

real	0m0.058s
user	0m0.012s
sys	0m0.048s

Como véis muestra el tiempo total de ejecución, y el que ha sido empleado por el usuario y el sistema.

Mostrar el tamaño ocupado por la carpeta “Peliculas” y el tiempo que ha costado sacarlo:

$ time du -shc Peliculas/
12G	Peliculas/
12G	total

real	0m0.007s
user	0m0.000s
sys	0m0.008s

Linux: Ejecuta y visualiza comandos periódicamente con ‘watch’


Antes de conocer el comando watch de Linux, si por ejemplo quería revisar cada pocos segundos las consultas MySQL que se estaban ejecutando en una máquina, tenía que estar continuamente ejecutando el comando en la terminal para ver la salida del mismo:

# mysqladmin processlist -u root -pxxxx
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| Id     | User      | Host      | db    | Command | Time  | State | Info             |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| 205709 | root      | localhost |       | Query   | 0     |       | show processlist |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+

# mysqladmin processlist -u root -pxxxx
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| Id     | User      | Host      | db    | Command | Time  | State | Info             |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| 205709 | root      | localhost |       | Query   | 0     |       | show processlist |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+

# mysqladmin processlist -u root -pxxxx
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| Id     | User      | Host      | db    | Command | Time  | State | Info             |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| 205709 | root      | localhost |       | Query   | 0     |       | show processlist |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+

Esta lógicamente no es la forma óptima de realizar la tarea. En el momento que necesitamos supervisar la salida de un comando periódicamente o ejecutarlo, lo mejor es utilizar “watch”. Watch es un comando que permite especificar un intervalo de tiempo, que será el que especificará cada cuanto ejecutaremos el comando que pasamos como argumento.

Si quisiera ejecutar el comando anterior cada 4 segundos y ver su salida por pantalla, podría hacerlo del siguiente modo:

# watch -n 4 'mysqladmin processlist -u root -pxxxx'

Y automáticamente vería lo siguiente, que refrescaría cada 4 segundos (el intervalo de segundos se especifica con la opción -n , por defecto 2 segundos):

Every 4,0s: mysqladmin processlist -u root -pxxxxx                                         Sat Oct 24 19:14:27 2009

+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| Id     | User      | Host	 | db    | Command | Time  | State | Info             |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+
| 205717 | root      | localhost |	 | Query   | 0     |	   | show processlist |
+--------+-----------+-----------+-------+---------+-------+-------+------------------+

A partir de aquí ya podéis encontrarle muchas más utilidades, como por ejemplo ver cada 2 segundos la memoria utilizada:

# watch free -m

O ver como cambia el contenido de una carpeta en concreto:

# watch -d ls -l 

En definitiva, un excelente comando que puede resultar de gran utilidad en el día a día.

Comando tr (unix): convertir mayúsculas a minúsculas y viceversa


Un truco rápido con el comando Unix tr, vamos a convertir las letras mayúsculas a minúsculas de un fichero.

Fichero test.txt:

$ cat test.txt
minusculas
MAYUSCULAS

Convertir mayúsculas en minúsculas del fichero test.txt:

$ cat test.txt | tr [:upper:] [:lower:]
minusculas
mayusculas

Convertir minúsculas en mayúsculas del fichero test.txt:

$ cat test.txt | tr [:lower:] [:upper:]
MINUSCULAS
MAYUSCULAS

Por supuesto, el comando tr nos ofrece muchas más opciones para transformación de carácteres, os dejo la ayuda del comando, recordad que en las páginas man hay mucha más información.

$ tr --help
Modo de empleo: tr [OPCIÓN]... CONJUNTO1 [CONJUNTO2]
Traducir, comprimir, y/o borrar caracteres de la entrada estándar,
escribiendo a la  entrada estándar.

  -c, -C, --complement    primer compliment SET1
  -d, --delete            borrar caracteres en SET1, no traducir
  -s, --squeeze-repeats   reemplazar cada secuencia de entradas de un caracter repetido
                            esta es una lista de SET1 con una sóla coincidencia
                            de ese caracter
  -t, --truncate-set1     primero truncar SET1 a la longitud de SET2
      --help     muestra esta ayuda y finaliza
      --version  informa de la versión y finaliza

Los CONJUNTOs se especifican como cadenas de caracteres. La mayoría se
representan a sí mismos.
Las secuencias válidas son las siguientes:

  \NNN            carácter con valor octal NNN (de uno a tres dígitos)
  \\              barra invertida
  \a              pitido audible (BEL)
  \b              espacio hacia atrás
  \f              salto de página
  \n              salto de línea
  \r              retorno de carro
  \t              tabulación horizontal
  \v              tabulación vertical
  CAR1-CAR2       todos los caracteres comprendidos entre CAR1 y CAR2 contados
                  en orden ascendente
  [CAR*]          en CONJUNTO2, copias de CAR hasta que se alcance la longitud
                  de CONJUNTO1
  [CAR*REPITE]    copia REPITE veces CAR; REPITE es octal si comienza con 0
  [:alnum:]       todas las letras y dígitos
  [:alpha:]       todas las letras
  [:blank:]       todos los espacios en blanco horizontales
  [:cntrl:]       todos los caracteres de control
  [:digit:]       todos los dígitos
  [:graph:]       todos los caracteres imprimibles, sin incluir el espacio
  [:lower:]       todas las letras minúsculas
  [:print:]       todos los caracteres imprimibles, incluyendo el espacio
  [:punct:]       todos los caracteres de puntuación
  [:space:]       todos los espacios en blanco horizontales y verticales
  [:upper:]       todas las letras mayúsculas
  [:xdigit:]      todos los números hexadecimales
  [=CAR=]         todos los caracteres que son igual que CAR

Se produce la traducción si no se especifican CONJUNTO1 y CONJUNTO2, siempre
y cuando no aparezca la opción -d. -t se puede usar sólo al traducir.
CONJUNTO2 se expande a la longitud de CONJUNTO1, repitiendo su último
carácter tantas veces como sea necesario.  Los caracteres que sobran en
CONJUNTO2 no se tienen en cuenta. Solamente se garantiza que [:lower:]
y [:upper:] sean expandidos en orden ascendente; si se usa en
CONJUNTO2 al traducir, sólo se pueden usar en parejas, para
especificar conversión a mayúsculas.  -s usa CONJUNTO1 si no se está
traduciendo ni borrando; si no, la compresión usa CONJUNTO2 después de
la traducción o el borrado.

nohup: Mantiene la ejecución de un comando pese a salir de la terminal


El comando nohup permite mantener la ejecución de un comando (el cual le pasamos como un argumento) pese a salir de la terminal (logout), ya que hace que se ejecute de forma independiente a la sesión.

Básicamente, lo que hace es ignorar la señal HUP (señal que se envía a un proceso cuando la terminal que lo controla se cierra), esto implica que aunque cerremos la terminal, el proceso se siga ejecutando.

La propia ayuda disponible en la shell (y en las páginas man) nos ayudará a entender el modo de ejecución del comando:

$ nohup --help
Modo de empleo: nohup ORDEN [ARGUMENTO]...
       o bien:  nohup OPCIÓN
Ejecuta ORDEN, descartando las señales de colgar.

      --help     muestra esta ayuda y finaliza
      --version  informa de la versión y finaliza

si la entrada estándar es una terminal, redirigirla desde /dev/null.
si la salida estándar es una terminal, añadir la salida a `nohup.out` si es posible,
en caso contrario a `$HOME/nohup.out`.
si los errores van a una terminal, redirigirlos a la salida estándar.
Para guardar la salida a FILE, use `nohup COMMAND > FILE`

Un ejemplo sencillo sería la ejecución en segundo plano de un script cualquiera, gracias al comando nohup permitiremos la continuidad de la ejecución en caso de cualquier problema con la sesión, shell de ejecución, etc:

$ nohup ./miscript.sh &

Por defecto, la salida del comando, que normalmente aparecería directamente en la terminal, será procesada a un fichero llamado nohup.out que aparecerá en la ruta donde nos encontremos al ejecutar el comando.

Truco shell: Ejecutar un comando con los argumentos del ejecutado anteriormente


Hoy os dejo un interesante truco para aquellos que trabajan de forma continuada en shell. Básicamente consiste en la capacidad de utilizar los argumentos del comando que acabamos de ejecutar en el siguiente sin necesidad de nombrarlos. Voy a explicarlo con un ejemplo que se verá más fácil:

En primera instancia ejecutamos:

$ mkdir ~/test

Hemos creado una carpeta llamada “test” en nuestra home, ahora para acceder a ella lo normal sería hacer:

$ cd  ~/test

Pero podemos acceder de este modo, usando los argumentos del comando anterior:

$ cd !*
cd ~/test
$~/test$

Podemos ser más específicos, “!*” se utiliza para repetir todos los argumentos, pero también podemos especificar la utilización de solamente uno de ellos, por ejemplo el segundo “!:2″, o el último “!$”.

FreeBSD: Activar color en la salida de LS


Para activar los colores en la salida del comando LS solamente tenéis que añadir la opción G a ls, ejemplo:

ls -G

Lo mejor es crear un alias, sería del siguiente modo:

Bash (.bashrc):

alias ls='ls –G'

Csh (.cshrc):

alias l         ls -G

En algunos casos es necesario cambiar la variable TERM a xterm-color ó xterm-color:

export TERM=xterm-color
export TERM=xterm

Truco shell Unix: quitar líneas en blanco de un fichero con grep


grep . fichero > fichero2

Con el comando citado arriba conseguiremos pasar al fichero2 las líneas que contengan caracteres del fichero 1, o lo que es lo mismo, pasar todo excepto las líneas en blanco. Opción interesante si no nos manejamos con comandos como sed, awk, etc.

El comando rsync


El comando rsync sustituye al obsoleto rcp (remote-copy). Se trata de un comando de gran flexibilidad, permite encriptar las trasferencias de datos a través de ssh, permite realizar copias desde una máquina local a una remota (y viceversa), de local a local, y entre servidores rsync.

Lo que diferencia a rsync de otros comandos o utilidades es que usa un algoritmo mediante el cual, cuando se copian datos, solamente se copian aquellos que han sido modificados o que han cambiado desde la última vez que se copiaron. Si un fichero a cambiado solamente copiará aquellos datos diferentes entre el fichero antiguo y el nuevo. Esto supone un ahorro considerable de ancho de banda, tiempo y carga del sistema.

Como siempre, toda la información y opciones de rsync en su página man:

man rsync

Os dejo algunos ejemplos para que os vayáis familiarizando con la herramienta, esto y mucho más en la web oficial de rsync.

backup a un servidor de backups central cada 7 días de forma incremental

#!/bin/sh

# This script does personal backups to a rsync backup server. You will end up
# with a 7 day rotating incremental backup. The incrementals will go
# into subdirectories named after the day of the week, and the current
# full backup goes into a directory called "current"
# tridge@linuxcare.com

# directory to backup
BDIR=/home/$USER

# excludes file - this contains a wildcard pattern per line of files to exclude
EXCLUDES=$HOME/cron/excludes

# the name of the backup machine
BSERVER=owl

# your password on the backup server
export RSYNC_PASSWORD=XXXXXX

########################################################################

BACKUPDIR=`date +%A`
OPTS="--force --ignore-errors --delete-excluded --exclude-from=$EXCLUDES
      --delete --backup --backup-dir=/$BACKUPDIR -a"

export PATH=$PATH:/bin:/usr/bin:/usr/local/bin

# the following line clears the last weeks incremental directory
[ -d $HOME/emptydir ] || mkdir $HOME/emptydir
rsync --delete -a $HOME/emptydir/ $BSERVER::$USER/$BACKUPDIR/
rmdir $HOME/emptydir

# now the actual transfer
rsync $OPTS $BDIR $BSERVER::$USER/current

Backup a un disco spare

I do local backups on several of my machines using rsync. I have an
extra disk installed that can hold all the contents of the main
disk. I then have a nightly cron job that backs up the main disk to
the backup. This is the script I use on one of those machines.

    #!/bin/sh

    export PATH=/usr/local/bin:/usr/bin:/bin

    LIST="rootfs usr data data2"

    for d in $LIST; do
	mount /backup/$d
	rsync -ax --exclude fstab --delete /$d/ /backup/$d/
	umount /backup/$d
    done

    DAY=`date "+%A"`

    rsync -a --delete /usr/local/apache /data2/backups/$DAY
    rsync -a --delete /data/solid /data2/backups/$DAY

The first part does the backup on the spare disk. The second part
backs up the critical parts to daily directories.  I also backup the
critical parts using a rsync over ssh to a remote machine.

mirroring vger CVS tree

The vger.rutgers.edu cvs tree is mirrored onto cvs.samba.org via
anonymous rsync using the following script.

    #!/bin/bash

    cd /var/www/cvs/vger/
    PATH=/usr/local/bin:/usr/freeware/bin:/usr/bin:/bin

    RUN=`lps x | grep rsync | grep -v grep | wc -l`
    if [ "$RUN" -gt 0 ]; then
	    echo already running
	    exit 1
    fi

    rsync -az vger.rutgers.edu::cvs/CVSROOT/ChangeLog $HOME/ChangeLog

    sum1=`sum $HOME/ChangeLog`
    sum2=`sum /var/www/cvs/vger/CVSROOT/ChangeLog`

    if [ "$sum1" = "$sum2" ]; then
	    echo nothing to do
	    exit 0
    fi

    rsync -az --delete --force vger.rutgers.edu::cvs/ /var/www/cvs/vger/
    exit 0

Note in particular the initial rsync of the ChangeLog to determine if
anything has changed. This could be omitted but it would mean that the
rsyncd on vger would have to build a complete listing of the cvs area
at each run. As most of the time nothing will have changed I wanted to
save the time on vger by only doing a full rsync if the ChangeLog has
changed. This helped quite a lot because vger is low on memory and
generally quite heavily loaded, so doing a listing on such a large
tree every hour would have been excessive.

Backup automatizado de home

I use rsync to backup my wifes home directory across a modem link each
night. The cron job looks like this

    #!/bin/sh
    cd ~susan
    {
    echo
    date
    dest=~/backup/`date +%A`
    mkdir $dest.new
    find . -xdev -type f \( -mtime 0 -or -mtime 1 \) -exec cp -aPv "{}"
    $dest.new \;
    cnt=`find $dest.new -type f | wc -l`
    if [ $cnt -gt 0 ]; then
      rm -rf $dest
      mv $dest.new $dest
    fi
    rm -rf $dest.new
    rsync -Cavze ssh . samba:backup
    } >> ~/backup/backup.log 2>&1

note that most of this script isn't anything to do with rsync, it just
creates a daily backup of Susans work in a ~susan/backup/ directory so
she can retrieve any version from the last week. The last line does
the rsync of her directory across the modem link to the host
samba. Note that I am using the -C option which allows me to add
entries to .cvsignore for stuff that doesn't need to be backed up.