Mostrando entradas con la etiqueta bash. Mostrar todas las entradas
Mostrando entradas con la etiqueta bash. Mostrar todas las entradas

Bash: Control de errores y debug

Recientemente hablamos acerca de las diferencias de usar /bin/bash o /usr/bin/env bash. No suele ser algo muy habitual, pero puede resultar de gran ayuda.
Hoy vamos a ver otro de esos pequeños trucos de bash, pero que puede resultar de gran ayuda. Estamos hablando del control de errores y de habilitar el modo debug.
Como suele ser habitual es los script en bash, tras inicializar el entorno, se suele poner el comando 'set -e', abreviatura de 'set -o errexit'.
#!/usr/bin/env bash
set -e

# Código bash a ejecutar...
En caso de que durante la ejecución del script aparezca algún error, inmediatamente detendrá la ejecución del script.

El método antes comentando suele ser útil para scripts de producción, donde se presupone que no van a existir errores y por lo tanto no es necesario saber exactamente lo que pasa. Sin embargo, cuando estamos escribiendo código, sí puede resultar muy útil tener habilitado el modo debug. Para eso, 'set -x' es la solución.
#!/usr/bin/env bash
set -x

# Código bash a ejecutar...

Nota: 'set -x' en el script es lo mismo que 'bash -x tu_script'.
Leer más

/bin/bash vs. /usr/bin/env bash

Cuando estamos programando un script en bash siempre solemos inicializarlo con la línea que indica que es eso, un script en bash. Esta línea a mayores nos indica el path del intérprete. Por norma general, suele ser siempre /bin/bash/usr/bin/bash. Este "o" es el que puede causarnos algunos problemas. Para evitarlo, podemos emplear el siguiente truco: llamar a la función de enviroment. Es decir, pasamos de comenzar el script típico,
#!/bin/bash

# Código bash a ejecutar...
A usar las variables de entorno, para que sea ésta la que localice el path exacto donde está bash.
#!/usr/bin/env bash

# Código bash a ejecutar...
Con esto lo que conseguimos es hacer el script más flexible y adaptable a otros entornos donde quizás bash no esté en la misma ruta.
Leer más

Grabación de sesiones de consola

No fui el primero, ni seré el último en preguntarse cómo grabar todo lo que estás haciendo en la consola de tu equipo Linux, par a continuación poder dejarlo a libre disposición.
hasta que conocí el software del que os voy a hablar hoy, la forma que tenía de hacerlo no era más que la de grabar toda la pantalla (o una región) y dejar luego el vídeo, por ejemplo en Youtube.
Pues bien, ahora ya no podrás decir que no conoces ttyrec, con el que podrás grabar todo el comportamiento de tu consola de una forma más limpia y rápida.

Instalación

ttyrec está disponible en prácticamente todos los repositorios oficiales de las principales distribuciones, así que para instalarlo,
shell> apt-get install ttyrec

Grabar

Comenzar una nueva sesión o grabación es muy sencillo. Únicamente tendremos que saber el nombre que le vamos a querer dar y a continuación,
shell> ttyrec -a git_usage.tty
Para pararla, emplearemos Control + c.

Reproducir

Una vez tengamos la grabación finalizada, tendremos un fichero que podemos reproducir las veces que queramos, únicamente tendremos que tener instalado ttyplay, que viene con el paquete ttyrec.
shell> ttyplay git_usage.tty
Por suerte, este tipo de ficheros, al almacenar texto plano ocupan muy poco, por lo que pasárselos a alguien es sencillo y no debería de darnos problema. De todas formas existen webs, como playterm.org que nos permiten subir el fichero e incrustarlo en una web o dejarlo público.

Referencias

Leer más

Deshabilitar la comprobación de discos en el arranque

Creo que a muchos, por no decir todos los que estemos leyendo esta entrada nos habrá pasado alguna vez, que tras reiniciar un equipo y teniendo prisa en que arranque, éste se pone a comprobar el disco en busca de problemas.
Esta tarea está por defecto en los sistemas de ficheros extN y reiserfs y, lógicamente, si está es por algo. Pero puesto que GNU/Linux es altamente configurable si deseamos que una partición nunca se compruebe, bien por que son muchos datos, bien por que lo hacemos nosotros manualmente, podemos indicárselo. Para ello existe el comando tune2fs.
shell> tune2fs -c0 -i0d /dev/sdXY
Según el manual, las opciones que le pasamos indican lo siguiente:
  • -c max-mount-counts
    Adjust the maximal mounts count between two filesystem checks. If max-mount-counts is 0 then the number of times the filesystem is mounted will be disregarded by e2fsck and the kernel.
  • -i interval-between-checks[d|m|w]
    Adjust the maximal time between two filesystem checks. No postfix or d result in days, m in months, and w in weeks.
    A value of zero will disable the time-dependent checking.
Como veis, en el man de tune2fs se explica el método para deshabilitar, aunque también recomienda no deshabilitarlo, ya que la comprobación del sistema de ficheros es algo importante, ya que garantiza la integridad y la consistencia de los datos.
Failure to do so may lead to filesystem corruption due to bad disks, cables, memory, or kernel bugs to go unnoticed until they cause data loss or corruption.
Así que ya sabéis, si necesitáis evitar que la máquina compruebe el disco tras un reinicio concreto, existen otras formas de hacerlo y si aun así queréis deshabilitarlo, tener presente los problemas futuros que pueda entrañar.
Leer más

Valores aleatorios en #bash

Recientemente descubrí una interesante variable bash, $RANDOM, que como muy bien su nombre indica, devuelve un número aleatorio entre 0 y 32767 cada vez que es llamada. Un ejemplo visual resulta más sencillo,
shell> echo $RANDOM
3721
Por supuesto, este número no es que nos sirva de mucho, ya que tomar decisiones en función de él es un poco complicado. Para hacerlo más útil, vamos a aplicarle el módulo, para que el valor devuelvo nos sirva ya de algo.
Por ejemplo, aplicando el módulo 2, tendremos una salida entre 0 y 1, por lo que nos serviría en un script para que se ejecute, según estadística, la mitad de las veces.
shell> echo $((RANDOM%2))
1
shell> echo $((RANDOM%2))
0
El módulo lo podemos aplicar sobre cualquier número, según el resultado que no interese.
Para ver que el ejemplo es más o menos real, nos fijamos en la siguiente salida,
shell> for i in {1..10000} ; do echo "$((RANDOM%2))"; done | sort | uniq -c
   4992 0
   5008 1
Si os interesan valores aleatorios en bash, $RANDOM es vuestra variable.
Leer más

Contando ocurrencias de una palabra

A cuántos de nosotros se nos habrá preguntado alguna vez, "¿cuántas veces se repite X comando en un fichero". Pues bien, la forma más simple de hacerlo, sin duda es con un sort y con un uniq, ambos comandos básicos presentes en cualquier sistema GNU/Linux. Vamos a ver un ejemplo de cómo usarlos juntos para que nos den las respuestas que precisamos.
Imaginémonos que nos interesa saber la shell que están empleando los usuarios de uno de nuestros sistemas. La forma más sencilla de averiguar esto es leyendo el fichero /etc/passwd, coger la última columna (si tenemos en cuenta una separación por ":") y luego contar las ocurrencias de cada una. Algo tal que esto,
shell> awk 'BEGIN{FS=":"} {print $7}' < /etc/passwd
/bin/bash
/bin/sh
/bin/sh
/bin/sh
/bin/sync
/bin/sh
...
Ya si nos interesa ser un poco más profesionales, podemos ordenarlas.
shell> awk 'BEGIN{FS=":"} {print $7}' < /etc/passwd | sort 
/bin/bash
/bin/bash
/bin/false
/bin/false
/bin/sh
/bin/sh
...
Pero imagínate que tienes 200 usuarios datos de alta, ir línea a línea contando podría hacerse eterno. Eso y que terminaríamos por perdernos. Así que la mejor idea es dejar una único ocurrencia y que sea el propio comando uniq el que las cuente,
shell> awk 'BEGIN{FS=":"} {print $7}' < /etc/passwd | sort | uniq -c 
 2 /bin/bash
 2 /bin/false
17 /bin/sh
 1 /bin/sync
 1 /usr/sbin/nologin
Rápido y sencillo.
Leer más

Forzar chequeo de disco en reinicio del sistema

Hoy os quiero presentar un truco tan interesante como sencillo. Hay muchas veces que nos interesa forzar un chequeo de disco cuando el sistema se reinicie, pero que por lo que sea, no podemos reiniciarlo en ese momento. Luego lo reiniciamos y se nos olvida de indicárselo en el parámetro del shutdown, con lo que seguimos en la misma.
Para evitar que eso nos suceda, podemos crear un fichero vacío en la raíz del sistema y que se llame forcefsck. Tan simple como eso y conseguiremos que en el próximo reinicio el sistema compruebe los discos, para a continuación borrar automáticamente dicho fichero.
shell> touch /forcefsck
Leer más

GeoIP desde bash

GeoIP es una base de datos de consulta de localizaciones IP, que dispone de múltiples lenguajes de programación para el acceso a los datos, desde php a python y como no iba a ser menos, también desde la shell de Linux se permiten las preguntas acerca de dónde es una IP concreta.
Lo primero que necesitamos, teniendo en cuenta que partimos de un sistema con geoip-database instalado, es instalar el binario para poder consultar los datos del fichero. Esto nos ofrecerá ya el software que vamos a emplear, geoiplookup y geoiplookup6, por si empleamos IPv6. Tanto la instalación como el uso es bastante sencillo e intuitivo. El paquete está en los repositorios de las principales distribuciones y el uso, simplemente necesitamos la IP de la que deseamos obtener la información.
shell> apt-get install geoip-bin
shell> geoiplookup 77.226.X.Y
GeoIP Country Edition: ES, Spain
Esta base de datos enorme de localizaciones está creada y mantenida por MaxMind, empresa que ofrece una versión "lite" (libre) y otra de pago.
En el caso de Debian Wheezy o la última Ubuntu (14.04), la versión de base de datos que trae es del 2013-08-27. Si por el contrario tenemos una Debian Squeeze, la versión es mucho más antigua, 2010-07-14, por lo que los datos que ahí aparecen pueden no ser del todo correctos. Por lo tanto, antes de ponernos a trabajar, debemos de actualizar las bases de datos. Para ello, recurrimos a la página oficial. Descargamos el fichero GeoLite Country y GeoLite City. El primero para actualizar el que ya tenemos y el segundo, para tener una mayor definición. Tras descargar ambos ficheros, los descomprimimos y los colocamos en el sitio oficial.
shell> cd ~/Descargas
shell> wget http://geolite.maxmind.com/GeoLiteCountry/GeoIP.dat.gz
shell> wget http://geolite.maxmind.com/GeoLiteCity.dat.gz
shell> gunzip GeoIP.dat.gz
shell> gunzip GeoLiteCity.dat.gz
shell> mv ~/Descargas/GeoIP.dat /usr/share/GeoIP/GeoIP.dat
shell> mv ~/Descargas/GeoLiteCity.dat /usr/share/GeoIP/GeoLiteCity.dat
Ahora ya tenemos una base de datos más completa y actualizada. Aunque nos faltarán datos, puesto que no pagamos la suscripción, sí es más moderna que la que trae el paquete.
Si ahora hacemos la misma prueba que antes, pero indicándole que emplee el fichero de localización por ciudad, tenemos lo siguiente,
shell> geoiplookup -f /usr/share/GeoIP/GeoLiteCity.dat 77.226.X.Y
GeoIP City Edition, Rev 1: ES, 58, Galicia, Orense, N/A...
Vemos que esta información ya es mucho más útil. No es lo mismo saber que alguien está en España, que que ese alguien está de Orense.
Aunque la integración con php, páginas web o cms no la voy a comentar, sí es bueno comentar la utilidad práctica de este comando, por ejemplo, para comprobar las IPs que consultan una determinada página web. Leyendo los logs de apache, ante un eventual ataque, podemos saber rápidamente de dónde provienen dichas peticiones. Así que con un poco de magia de scripting, tenemos algo tal que así,
for ip in `cat /var/log/apache/access.log | awk '{print $1}' | sort -n | uniq`
do
   echo -ne "$ip\t"
   geoiplookup -f /usr/share/GeoIP/GeoLiteCity.dat $ip
done
Donde el resultado es similar al que sigue,
222.77.229.X GeoIP City Edition, Rev 1: CN, 22, Beijing, Beijing, N/A...
222.77.242.X GeoIP City Edition, Rev 1: CN, 07, Fujian, Fuzhou, N/A...
222.79.153.X GeoIP City Edition, Rev 1: CN, 07, Fujian, Fuzhou, N/A...
222.87.129.X GeoIP City Edition, Rev 1: CN, 18, Guizhou, Guiyang, N/A...
223.219.152.X GeoIP City Edition, Rev 1: JP, 40, Tokyo, Tokyo, N/A...
223.240.142.X GeoIP City Edition, Rev 1: CN, 01, Anhui, Hefei, N/A...
223.27.200.X GeoIP City Edition, Rev 1: TH, 60, Surat Thani, Vibhavadi...
Puesto que estamos trabajando con la versión "lite", algunas de las IPs no están incluidas o actualizadas, pero para hacernos una idea general nos sirve.

Si esto te pareció útil, quizás te interesa saber cómo filtrar países con IPTables.
Leer más

Filtrar países con IPTables

Una de las cosas que más nos llama la atención a los administradores de sistemas, especialmente si tenéis acceso a equipos de Firewall es siempre la cantidad de ataques que se están recibiendo. Es cierto que la red no es un lugar cómodo ni pacífico. A los 5 minutos de conectar un equipo a una IP pública, éste ya comienza a recibir ataques. Nos guste o no, tenga lógica o no, la mayoría de los ataques a los equipos provienen de determinados países, llamémosle conflictivos, como puedes ser China, Rusia, etc. Por suerte para nosotros, GNU/Linux tiene un sistema de Firewall modular que permite añadir pequeñas mejoras. Hoy vamos a ver cómo filtrar los paquetes de determinados países gracias a xtables_addons.
xtables_addons es un sistema modular para el kernel que permite añadir funcionalidades sin parchear éste, gracias a la creación de módulos dinámicos (dkms), lo que evita tener que compilar y reiniciar el sistema. En determinadas distribuciones (Ubuntu y derivados) está disponible ya para instalación, mientras que en otras hay que compilarlos desde las fuentes. Puesto que el funcionamiento una vez instalado es el mismo, vamos a partir de una Ubuntu desde la que podamos simplificar la instalación.
shell> apt-get install xtables-addons-dkms
La instalación de este paquete llevará un poco de tiempo, puesto que crea los módulos para la versión del kernel que tengamos instalada. Gracias a dkms, si se actualiza el kernel, los módulos se volverán a reconstruir automáticamente. Una vez instalado xtables_addons, debemos instalar el paquete que simplifica la forma de procesar los paquetes de rangos de IPs de los países. Para ello,
shell> apt-get install libtext-csv-xs-perl
Ahora ya estamos listos para comenzar a trabajar y filtrar las conexiones entrantes o salientes de IPTables a determinados países. Lo primero será descargar las bases de datos de rangos IP de cada país. Para ello,
shell> cd /tmp
shell> /usr/lib/xtables-addons/xt_geoip_dl
Esto nos descargará dos ficheros, GeoIPv6.csv.gz y GeoIPCountryCSV.zip, que los procesará y dejará en el directorio actual un fichero más llamado GeoIPCountryWhois.csv, que es el que realmente nos va a interesar. Ahora tenemos que procesar este fichero .cvs para darle el formato adecuado y que xtables_addons e IPTables lo entiendan. Para hacer esto,
shell> mkdir -p /usr/share/xt_geoip/
shell> /usr/lib/xtables-addons/xt_geoip_build -D /usr/share/xt_geoip/ \
       GeoIPCountryWhois.csv
91027 entries total
    0 IPv6 ranges for A1 Anonymous Proxy
  102 IPv4 ranges for A1 Anonymous Proxy
    0 IPv6 ranges for A2 Satellite Provider
  425 IPv4 ranges for A2 Satellite Provider
    0 IPv6 ranges for AD Andorra
    8 IPv4 ranges for AD Andorra
    0 IPv6 ranges for AE United Arab Emirates
      ...
  485 IPv4 ranges for ZA South Africa
    0 IPv6 ranges for ZM Zambia
   43 IPv4 ranges for ZM Zambia
    0 IPv6 ranges for ZW Zimbabwe
   47 IPv4 ranges for ZW Zimbabwe
Llegados a este punto ya estamos listos para emplear el filtrado por países en IPTables. Lo único que debemos de hacer es emplear "-m geoip" y "--src-cc XX", siendo XX el código ISO del país (código ISO en Wikipedia).
Por ejemplo, para bloquear las conexiones entrantes desde IPs del rango de China (ISO CN), tendríamos que hacer algo como,
shell> iptables -A INPUT -m geoip --src-cc CN -j DROP
También se puede emplear este truco de geoip con las opciones habituales de IPTables,
shell> iptables -A INPUT \
       -p tcp -m tcp -m multiport --dports 80,443 \
       -m geoip --src-cc CN \
       -j DROP
Tras ello, podemos ver cómo quedaría nuestro Firewall configurado,
shell> iptables -L -n -v
Chain INPUT (policy ACCEPT 1644 packets, 2796K bytes)
pkts B target prot opt in out source    destination         
0    0 DROP   all  --  *  *   0.0.0.0/0 0.0.0.0/0 -m geoip --source-country CN
0    0 DROP   tcp  --  *  *   0.0.0.0/0 0.0.0.0/0 tcp multiport dports 80,443 -m ...

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts B target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 1423 packets, 221K bytes)
pkts B target prot opt in out source destination

Leer más

Controlando VirtualBox desde consola

En numerosas ocasiones hablamos en este blog sobre VirtualBox y la facilidad que éste tiene para la gestión de máquinas virtuales, especialmente en entornos domésticos. Personalmente no lo contemplo para algo que no sea desarrollo.
Desde mi punto de vista, uno de los mayores problemas que veo en vBox es la forma de arrancar y gestionar las máquinas; arrancas el interfaz gráfico, seleccionas la máquina y la inicias. Una vez comienza el proceso de arranque, ya se puede cerrar el software de lanzamiento. La ventana ejecuta se ejecuta en otro instancia que crear su propia ventana. No es que me moleste, pero no soy amigo de tener muchas ventanas abiertas, así que tenía que encontrar una forma de arrancar y gestionar las máquinas virtuales sin interfaz gráfico. Al fin y al cabo, a las máquinas Linux siempre me conecto vía ssh y a las máquinas con Windows no me conecto vía escritorio remoto.
Además de esto, poder gestionar las máquinas desde línea de comandos simplificaría el manejo de las mismas, especialmente en remoto, que ya no sería para nada necesario un interfaz gráfico.
Para hacerlo comencé a investigar un poco el comando VBoxManage, que es el encargado de hacer todos los trabajos a bajo nivel. Entonces descubrí la forma sencilla de poder arrancar una máquina, apagarla, saber qué máquinas tengo instaladas, cuales en ejecución, etc.
A continuación os dejo algunos de los comandos que más habitualmente supongo que se emplean en la gestión de máquinas virtuales, aunque para más información, mirar todas las opciones de VBoxManage.
  • Listar máquinas disponibles
    shell> VBoxManage list vms
    
  • Listar máquinas arrancadas
    shell> VBoxManage list runningvms
    
  • Reiniciar una máquina
    shell> VBoxManage controlvm uuid|vmname reset
    
  • Arrancar una máquina
    shel> VBoxManage startvm uuid|vmname --type headless
    
  • Apagar una máquina
    shell> VBoxManage controlvm uuid|vmname resume|poweroff
    
  • Información sobre una máquina
    shell> VBoxManage showvminfo uuid|vmname
    
  • Limitar el ancho de banda empleado por una máquina
    shell> VBoxManage bandwidthctl uuid|vmname add 'limit net' --type network --limit 1M
    
  • Registrar una nueva máquina virtual
    shell> VBoxManage registervm filename
    
  • Borrar una máquina virtual
    shell> VBoxManage unregistervm uuid|vmname --delete
    
Todos los procesos se lanzan sobre una máquina, bien por su nombre o por su uuid. En ambos casos éste debe ser único, por lo que no tendremos problemas de confundirnos de máquina sobre la que trabajar.
Leer más

Combinación de teclas en consola

Hace ya muchos años que el trabajo día a día lo desarrollo desde la consola de GNU/Linux y aún así no deja de sorprenderme. Hoy quiero compartir con vosotros un atajo de teclado, que personalmente descubrí de casualidad, y que me parece francamente interesante.
La combinación de teclas es ALT + Delete y sirve para borrar palabras completas en consola. Cuando estás tecleando un comando o una ruta y te has equivocado, esta combinación te permite borrar rápidamente toda la palabra.
shell> /home/javier/test.sh
                      # Presionamos ALT + Delete
shell> /home/javier/test
                      # Presionamos ALT + Delete
shell> /home/javier/
                      # Presionamos ALT + Delete
shell> /home/
Aunque puede parecer una chorrada, desde que la conozco me resulta muy cómoda.

Y tú, ¿qué combinaciones sueles usar? Déjalas en comentarios!
Leer más

Buenos hábitos en Linux Shell

Desde hace ya muchos años uso GNU/Linux de forma habitual, tanto en el trabajo como a nivel personal. Una de las grandes ventajas de usar este sistema operativo es la facilidad con la que puedes hacer las mismas cosas desde la consola. bash puede y debe ser tu gran aliado. Aunque a primera vista puede resultar feo trabajar en modo consola, sobre todo en los días que corren, la potencia que ello te da es tanta que da pena desaprovecharla.
Hoy os voy a dar algunos consejos acerca de buenos hábitos a la hora de emplear bash. Hay miles, así que este listado irá creciendo.
  1. Creación de directorios
    Es uno de los puntos más conflictivos a la hora de trabajar. El comando está claro, mkdir, pero la forma de crear árboles complicados puede ser muy diferente.
    Un mal ejemplo,
    shell> mkdir tmp
    shell> cd tmp
    shell> mkdir a
    shell> cd a
    shell> mkdir b
    shell> cd b
    shell> mkdir c
    shell> pwd
    ~/tmp/a/b/c
    
    Y ahora un buen ejemplo,
    shell> mkdir -p tmp/a/b/c
    
    Y otro ejemplo práctico más simple y útil que denota la potencia de emplear mkdir correctamente.
    shell> mkdir -p project/{lib,src,doc/{html,pdf},demo/stat}
  2. Descomprimir ficheros
    En GNU/Linux la extensión tar.gz suele ser muy empleada para trabajar con ficheros. Tras descargarla de donde corresponda, generalmente nos queda el fichero en la carpeta habitual de descargas, pero para trabajar con él, toca descomprimirlo. Una mala práctica es descomprimirlo directamente en dicha carpeta, ya que terminamos por dejar el directorio sucio, mientras que una buena práctica es emplear la opción -C del propio comando, que nos permite establecer la ruta completa donde será descomprimido, sin tener que mover el fichero descargado.
    shell> tar zxvf -C /tmp zabbix.tar.gz
    
  3. Entrecomillado de variables
    Hay que tener cuidado a la hora de definir y de entrecomillar una variable o su resultado. Así evitaremos sorpresas futuras.
    shell> mkdir -p test/{a,b}
    shell> ls test
    a  b
    shell> VAR="test/*"
    shell> echo $VAR
    test/a test/b
    shell> echo "$VAR"
    test/*
    shell> echo $VARa
    
    shell> echo "$VARa"
    
    shell> echo "${VAR}a"
    test/*a
    shell> echo ${VAR}a
    test/a
    
  4. Concatenar comandos siempre que sea posible
    Esta es una de las partes en las que más potencia tiene la shell de GNU/Linux, la concatenación de comandos. La salida de un comando puede ser la entrada de otro y así recursivamente, pero hay que tener mucho cuidado con lo que intentamos redirigir y hacerlo con mucha cabeza. Por ejemplo:
    1. No usar cat para lista y grep para filtrar. Filtrar directamente!
      shell> cat file.txt | grep "hola"       # mal
      shell> grep "hola" file.txt             # bien
      
    2. Evitar usar grep y luego contar líneas. Emplea las opciones de grep (-c)!
      shell> grep "hola" file.txt | wc -l  # mal
      shell> grep -v "hola" file.txt       # bien
      
    3. Emplea, siempre que sea posible awk y no grep. Es mucho más rápido!
      shell> ls -l /tmp/a/b/c | grep sep   # mal
      shell> ls -l | awk '$6 == "sep"'     # bien
      
  5. Emplea expresiones de control para concatenar comandos
    Si te interesa que un comando se ejecute siempre que el anterior se haya ejecutado correctamente, hazlo en una única línea. Y también al revés.
    1. La cadena && permite la ejecución si el comando anterior ha devuelto un status 0 (terminó correctamente).
      shell> cd /tmp && tar zxvf ~/archive.tar
      
    2. La cadena || indica que se haga el segundo comando si el primero no tuvo una salida 0 (correcta).
      shell> cd /tmp || mkdir /tmp && tar zxvf ~/archive.tar
      
  6. En scripts, comprueba recursos antes de emplearlo
    Si estás creando un script con acceso a ficheros, comprueba que estos existan antes de usarlos. Te evitarás malas jugadas!
    if [ -d "/Fichero/necesario" ]
    then
       ...
    else
       #fichero no existe!
    fi
    

La entrada Buenos hábitos en Linux Shell la puede leer en Puppet Linux.
Leer más

sudo vs. su

Primero fue su, luego llegó sudo y lo siguiente será... Desde que conozco GNU/Linux empleé su para poder acceder a una cuenta de usuario diferente a la mía y poder ejecutar o ver diferentes cosas. Con la expansión de Ubuntu, el comando sudo fue tomando cada vez más y más relevancia hasta llegar al punto de que su quedó, digámoslo así, deprecated. Sin embargo esto no es cierto y existen diferencias bastante sustanciales entre su y sudo. Vamos a verlas y en qué casos se debería usar cada uno.

su

su fue el primero de los comando que conocí para entrar en la cuenta de otro usuario, como ya dije antes. Y realmente es para lo que sirve. Permite al usuario cambiar la cuenta de usuario con la que está logueado sin tener que salir de la sesión que ya tiene. Aunque típicamente su se empleaba como comando para ascender a root, realmente permite acceder a cualquier usuario.
Al ejecutar su, éste pide la contraseña del usuario con el que queremos hacer login y no la contraseña de nuestro usuario. Si ésta es correcta, entones el proceso que se ejecute es muy similar al de login (idéntico si empleamos su - ). Carga las variables todas que le corresponden al nuevo usuario (HOME; USER; SHELL; TERM; etc.) y hasta que se cierre la sesión, todos los comandos que se ejecuten tienen los permisos del nuevo usuario.
javier@shell> su -
Contraseña:
root@shell> 
Y con su no solamente se puede acceder a un usuario root, sino también a un usuario normal, siempre que se sepa su contraseña. Por lo tanto, las contraseñas deben de ser compartidas al emplear su.
javier@shell> su - test
Contraseña:
test@shell>

sudo

sudo es un comando directamente relacionado con su y que en realidad tiene la misma función, permitir a un usuario ejecutar comandos en nombre de otro. La gran diferencia es que el comando que se ejecuta con sudo debe estar previamente autorizado por el administrador (fichero /etc/sudoers) y que la contraseña que te solicita el comando es la de tu propio usuario y no la del otro usuario. Esta es la principal ventaja, en sudo no se comparten contraseñas.
javier@shell> sudo vi file
[sudo] password for javier: 

¿Cuál debes usar?

Esto realmente depende de cada uno y de cada sistema. Por seguridad quizás lo más lógico es emplear sudo. El administrador deja únicamente permisos para ejecutar determinados comandos, por lo que el riesgo de hacer algo desastroso en el sistema se redice mucho. A mayores, también es mejor, puesto que no hay que compartir contraseñas entre los usuarios.
Sin embargo, si lo que necesitas es trabajar como otro usuario puede terminar por resultar mucho más lógico emplear su que estar constantemente llamando a sudo.

La entrada sudo vs. su la puedes leer en Puppet Linux.
Leer más

Auto-completar comandos sudo

Si sois usuarios habituales de Ubuntu o derivadas de ésta distro, lo más probable es que este truco la os funcione y por lo tanto no os sirva para mucho. Sino, terminar de leer el post que quizás os pueda ser de gran ayuda.
Por defecto, la shell de GNU/Linux te ayuda a autocompletar los comandos que escribes simplemente con presionar la tecla "Tab", pero esto no sucede así si lo precedes del comando sudo. En ese caso, el autocompletado ya desaparece y si no sabemos el comando exacto a escribir la cosa se complica. Para poder tener el autocompletado con sudo, simplemente debéis de agregar la siguiente condición a vuestro fichero ~/.bashrc.
if [ "$PS1" ]; then 
   complete -cf sudo 
fi
Y disfrutar del autocompletado para sudo.

La entrada Auto-completar comandos sudo la puedes leer en Puppet Linux.
Leer más

Matar procesos por usuario

En post anteriores vimos cómo poder matar los procesos SSH de un usuario y ahí hicimos ya uso del comando pkill. Hoy vamos a ver otro truco de dicho comando, que no es otro que poder matar todos los procesos de un usuario.
Sí, efectivamente, si un usuario está haciendo un uso muy abusivo de CPU o memoria y queremos matar todos sus procesos de forma rápida y eficaz lo podemos hacer tal que así,
shell> pkill -u user
Aunque ojo! Matará TODOS los procesos de dicho usuario, sin contemplaciones y sin previo aviso, así que antes de hacerlo, pensar en qué vais a hacer ;-)
Leer más

Coloreando log's

Una de las partes más importantes de los sistemas GNU/Linux es fa facilidad que tiene este de saber todo lo que pasa en el sistema. Syslog está prácticamente integrado en todo el software que existe y por lo tanto saber algo de nuestro sistema es simplemente cuestión de ir a un log para verlo. De ahí la vital importancia de syslog/rsyslog y de la carpeta /var/log.
Sin embargo, fijo que a todos nos ha pasado, cuando tenemos que mirar muchas líneas de log puede resultar un poco monótono e incluso molesto no tener unos colores que te vayan indicando las palabras clave sobre las que deberías fijarte más. Puesto que los ficheros de log son texto plano, su contenido se puede listar de muchas formas: tail, cat, less, more, etc. pero ninguno de estos colorea la salida. Así que vamos a ver cómo conseguir una salida de colores para nuestro log.
Para empezar vamos a instalar ccze, un paquete que se encargará de dar color a nuestro contenido.
shell> apt-get install ccze
Tras su instalación ya tenemos listo el sistema de coloreado y podemos hacer lo siguiente para ver el log,
shell> ccze -A < /var/log/syslog
Puesto que esta forma de ver los log's puede no resultar 100% cómoda, vamos a crear una pequeña función en el alias de nuestro usuario que haga lo mismo, pero de forma más sencilla. Para hacerlo debemos editar el fichero ~/.bashrc y agregar las siguiente líneas al final del mismo.
log() {
   ccze -A < $1 | less -R
}
Ahora que ya tenemos la nueva función creada, le indicamos a nuestro usuario que vuelva a leer el contenido de dicho fichero, para que tenga la nueva función disponible,
shell> source ~/.bashrc
Y ya podemos hacerlo siguiente,
shell> log /var/log/syslog
May 24 13:58:02 se groupadd[922]: new group: name=postdrop, GID=106
May 24 14:00:16 se groupadd[128]: group added to /etc/group: name=scanner, GID=107
May 24 14:00:16 se groupadd[128]: group added to /etc/gshadow: name=scanner
May 24 14:00:16 se groupadd[128]: new group: name=scanner, GID=107
May 24 14:00:18 se groupadd[147]: group added to /etc/group: name=messagebus, GID=108
May 24 14:00:18 se groupadd[147]: group added to /etc/gshadow: name=messagebus
May 24 14:00:18 se groupadd[147]: new group: name=messagebus, GID=108
Lógicamente, en la función log yo empleo less, pero cada uno que emplee el paginador con el que más cómodo se sienta.
A mayores de colorear, el comando ccze tiene también alguna que otra ventaja, como puede ser la conversión automática de fechas en UnixTime a formato legible automáticamente. Este tipo de fechas nos las podemos encontrar en ficheros de log de Squid o de Zabbix.

La entrada Coloreando log's la puedes leer en Puppet Linux.
Leer más

Cambio de nombre del interfaz de red en GNU/Linux

El otro día la tarjeta de red integrada de la placa base de mi desktop dejó de dar señales de vida, por lo que para seguir conectado, tuve que adquirir una nueva. Tras el cambio y al encender mi sistema, Debian, la tarjeta de red ahora se llamaba eth2. Esto no me suponía ningún tipo de problema, pero la mayor parte del software que empleo, por defecto usa eth0 para operar y si quieres indicar otro interfaz de red, debes indicárselo manualmente (típica opción -i ethX). Como mi tarjeta eth0 estaba 100% muerta y no iba a volver, opté por cambiarle el nombre a eth2 y ponerle el de la anterior, para así tener un sistema sin cambios.
Debian, al igual que la mayoría de los sistemas Linux actuales emplean udev para controlar los dispositivos, por lo que la solución para cambiarle el nombre era ir al fichero de configuración (/etc/udev/rules.d/70-persistent-net.rules) y cambiar el nombre eth0 <-> eth2. Un pequeño cambio que tras un rápido reinicio, me permite volver a disfrutar de eth0 en mi sistema.
shell> ifconfig
eth0      Link encap:Ethernet  HWaddr 00:e0:4c:66:98:20  
          inet addr:192.168.1.33  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::2e0:4cff:fe66:9820/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:157686 errors:0 dropped:0 overruns:0 frame:0
          TX packets:163422 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:93148464 (88.8 MiB)  TX bytes:35958264 (34.2 MiB)
          Interrupt:20 Base address:0x2000 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:110 errors:0 dropped:0 overruns:0 frame:0
          TX packets:110 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:11731 (11.4 KiB)  TX bytes:11731 (11.4 KiB)

Leer más

Mimando y controlando los discos

Los discos duros son una de las partes fundamentales de nuestros equipos. Efectivamente, al igual que sin procesador o RAM, un equipo sin disco no puede funcionar (salvemos las distros en live), pero el disco sin embargo es la parte más fundamental por que es donde guardamos toda la información. Controlar el estado de vida del disco es muy importante, al igual que es hacer una buena copia de seguridad de todos nuestros datos. Desde GNU/Linux tenemos la posibilidad de vigilar los discos de forma sencilla con la utilidad smartmontools. Gracias a estar magnífica herramienta podemos obtener una serie de parámetros sobre los discos, desde temperatura hasta número de horas que lleva en funcionamiento. Y también, como era de esperar, recibir alertas en caso de que el disco esté dando algún tipo de fallo.
Vamos a comenzar por instalarlo. smartmontools está prácticamente disponible en los repositorios de cualquier distribución. En Debian/Ubuntu,
shell> apt-get install smartmontools
Tras esto, ya tenemos disponible el comando smartctl y el daemon smartd. Vamos a comenzar por ver la información que se puede extraer con el comando y luego veremos cómo configurar el daemon para que nos alerte de situaciones anómalas en los discos del equipo.
  • Información general
    Con la opción -i obtenemos información general del disco en cuestión. Versión del firmware, dispositivo, modelo, número de serie, etc.
    shell> smartctl -i /dev/sda
    === START OF INFORMATION SECTION ===
    Model Family:     Western Digital Caviar SE Serial ATA family
    Device Model:     WDC WD1600JS-08NCB1
    Serial Number:    WD-WMANM7963047
    Firmware Version: 10.02E01
    User Capacity:    160,041,885,696 bytes
    Device is:        In smartctl database [for details use: -P show]
    ATA Version is:   7
    ATA Standard is:  Exact ATA specification draft version not indicated
    Local Time is:    Mon Apr  1 11:26:09 2013 CEST
    SMART support is: Available - device has SMART capability.
    SMART support is: Enabled
    
  • Información detallada
    La opción -a nos ofrece la misma información que la anterior y a mayores más detalles como las horas de funcionamiento, la temperatura, veces que se ha encendido, etc.
    shell> smartctl -a /dev/sda
    === START OF INFORMATION SECTION ===
    Model Family:     Western Digital Caviar SE Serial ATA family
    Device Model:     WDC WD1600JS-08NCB1
    Serial Number:    WD-WMANM7963047
    Firmware Version: 10.02E01
    User Capacity:    160,041,885,696 bytes
    Device is:        In smartctl database [for details use: -P show]
    ATA Version is:   7
    ATA Standard is:  Exact ATA specification draft version
    Local Time is:    Mon Apr  1 11:28:57 2013 CEST
    SMART support is: Available - device has SMART capability.
    SMART support is: Enabled
    
    === START OF READ SMART DATA SECTION ===
    SMART overall-health self-assessment test result: PASSED
    See vendor-specific Attribute list for marginal Attributes.
    
    ...
    
    SMART Attributes Data Structure revision number: 16
    Vendor Specific SMART Attributes with Thresholds:
    ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE
      1 Raw_Read_Error_Rate     0x000f   200   200   051    Pre-fail
      3 Spin_Up_Time            0x0003   179   178   021    Pre-fail
      4 Start_Stop_Count        0x0032   100   100   000    Old_age
      5 Reallocated_Sector_Ct   0x0033   200   200   140    Pre-fail
      7 Seek_Error_Rate         0x000f   200   200   051    Pre-fail
      9 Power_On_Hours          0x0032   044   044   000    Old_age
     10 Spin_Retry_Count        0x0013   100   100   051    Pre-fail
     11 Calibration_Retry_Count 0x0012   100   100   051    Old_age
     12 Power_Cycle_Count       0x0032   100   100   000    Old_age
    190 Airflow_Temperature_Cel 0x0022   064   041   045    Old_age
    194 Temperature_Celsius     0x0022   111   088   000    Old_age
    196 Reallocated_Event_Count 0x0032   200   200   000    Old_age
    197 Current_Pending_Sector  0x0012   200   200   000    Old_age
    198 Offline_Uncorrectable   0x0010   200   200   000    Old_age
    199 UDMA_CRC_Error_Count    0x003e   200   200   000    Old_age
    200 Multi_Zone_Error_Rate   0x0009   200   200   051    Pre-fail
    
    SMART Error Log Version: 1
    No Errors Logged
    
    SMART Self-test log structure revision number 1
    Num  Test_Description  Status              Remaining  LifeTime(h)
    # 1  Short offline     Completed without error   00%     41414
    
    ...
    
  • Test de estado
    La opción -H realiza un pequeño test que indica si el estado del disco es correcto
    shell> smartctl -H /dev/sda
    === START OF READ SMART DATA SECTION ===
    SMART overall-health self-assessment test result: PASSED
    
    o incorrecto y está a punto de morir.
    shell> smartctl -H /dev/sda
    === START OF READ SMART DATA SECTION ===
    SMART overall-health self-assessment test result: FAILED!
    
  • Test con datos relevantes
    smartctl también se puede programar para que realice un test al disco y obtener más datos. Dependiendo del test a realizar la información se devolverá en el momento o tardará en realizarse.
    shell> smartctl -t short /dev/sda
    === START OF OFFLINE IMMEDIATE AND SELF-TEST SECTION ===
    Testing has begun.
    Please wait 2 minutes for test to complete.
    Test will complete after Mon Apr 5 18:28:37 2013
    
    Use smartctl -X to abort test.
    
    En caso de que tarde en devolvernos los datos, estos podrán ser consultados a posteriori tal que así,
    shell> smartctl -l selftest /dev/sda
    === START OF READ SMART DATA SECTION ===
    SMART Self-test log structure revision number 1
    Num  Test_Description  Status              Remaining  LifeTime(h)
    # 1  Short offline   Completed without error     00%     41414
    
  • Más información sobre smartctl en la página de su manual.
smartmontools también incluye un pequeño demonio que permite ejecutarse, controlar y enviar información del estado de los discos que le indiquemos que controle. Por defecto dicha información la enviará a syslog. Para configurar el daemon tendremos que editar el fichero /etc/default/smartmontools,
enable_smart="/dev/sda /dev/sdb"
start_smartd=yes
Y arrancar el daemon.
shell> /etc/init.d/smartmontools start
La primera variable nos indica los diferentes discos a monitorizar y la segunda permite que se arranque como servicio. A partir de ahora nos irá dando información de los discos y en caso de que hay algo "raro" en los mismos nos alertará por syslog. Por ejemplo,
Device: /dev/sda, FAILED SMART self-check. BACK UP DATA NOW!
Device: /dev/sda, Failed SMART usage Attribute: 5 Reallocated_Sector_Ct.
Device: /dev/sda, Self-Test Log error count increased from 4 to 5
Espero que os sea de utilidad y acordaros: BACK UP DATA NOW!

La entrada Mimando y controlando los discos la puedes leer en Puppet Linux.
Leer más

Formato de fechas en bash

Cada vez que tengo que manejar una fecha en GNU/Linux sé qué comando usar, date, pero cada vez que hay que darle un formato me pasa lo mismo. ¿Cómo se hacía para que saliera...? Así que a modo de chuleta me he escrito esta entrada donde dejaré plasmado el uso del comando date, así como los formatos de salida que soporta dicho comando.
Al ejecutar date en bash se obtiene ya la salida con la fecha actual completa,
shell> date
Wed Mar 29 19:32:29 CET 2013
El problema viene cuando deseamos sacar sólo una parte de dicha fecha, el año, las horas, la zona horaria, etc. Para hacer eso hay que emplear los acondicionadores de formato que se muestran en la tabla inferior e indicarle a date que los use con un +"". Vamos a poner algún ejemplo que nos ayude a esclarecer el empleo de dichos formatos.
  • Año-Mes-Día
    shell> date +"%Y-%m-%d"
    2013-03-27
    
  • Hora:Minutos:Segundos
    shell> date +"%T"
    10:49:28
    
  • Hora en formato 12
    shell> date +"%r"
    10:36:06 AM
    
Aprovechando esta entrada, también vamos a explicar cómo obtener con el mismo comando otra fecha que no sea la actual, ya bien sea una fecha futura o una pasada. Para conseguir hacer eso, debemos de usar la opción --date='...'. Esta opción es 100% compatible con el formato de fechas explicado con antelación.
  • Día de ayer
    shell> date +"%Y-%m-%d"
    2013-03-27
    shell> date --date='-1 day' +"%Y-%m-%d"
    2013-03-26
    
  • El mes pasado
    shell> date --date='-1 month' +"%Y-%m-%d"
    2013-02-27
    
  • El año que viene
    shell> date --date='+1 year' +"%Y-%m-%d"
    2014-03-27
    
Y como nota final, queda a continuación.
Formato
Significado
%%Imprime %.
%aAbreviatura del día de la semana, respetando el idioma.
Ejemplo: Sun.
%ADía completo de la semana. Respeta el idioma.
Ejemplo: Sunday.
%bAbreviatura del mes.
Ejemplo: Jan
%BNombre del mes completo.
Ejemplo: January
%cImprime la fecha y la hora respetando el idioma.
Ejemplo: Thu Mar 3 23:05:56 2013.
%CImprime el siglo. Tiene el mismo significado que "%Y", excepto que no muestra los dos últimos dígitos.
Ejemplo: 20.
%dDía del mes.
Ejemplo: 02.
%DFecha. Mismo significado que "%m/%d/%y".
%eDía del mes. Es lo mismo que "%_d".
%FFecha completa. Es lo mismo que "%Y-%m-%d".
%gÚltimos 2 dígitos del año, respetando el formato ISO de número de semanas.
%GAño completo, respetando el formato ISO de número de semanas.
%hAbreviatura del mes.
Ejemplo: Jan
%HHora (00...23).
%IHora (01...12).
%jDía del año (001...206).
%kHora (0...23).
%lHora (1...12).
%mMes (01...12).
%MMinutos (00...59).
%nLínea en blanco
%NNanosegundos (000000000...999999999)
%pImprime el tipo de hora local. AM o PM.
Si es desconocido, no saca nada.
%PLo mismo que "%p", pero en minúsculas.
%rHora exacta en formato 12 horas.
Ejemplo: 11:11:11 AM.
%RImprime horas, en formato 24 horas y minutos. Es lo mismo que "%H:%M".
%sSegundos desde 1970-01-01 00:00:00 UTC.
%SSegundos (00...60).
%tTabulación.
%THora; lo mismo que "%H:%M:%S".
%uDía de la semana (1...7). El 1 se corresponde a Lunes.
%UNúmero de semana del año (00...53). Se consideran el Domingo primer día de la semana.
%VISO número de la semana (01...53). El Lunes es el primer día de la semana.
%wDía de la semana (0...6). El 0 es Domingo.
%WNúmero de semana del año (00...53). El Lunes es el primer día de la semana.
%xImprime la fecha de acuerdo con el formato local.
Ejemplo: 03/24/13.
%XImprime la hora en formato local.
Ejemplo: 16:15:52.
%yÚltimos dos dígitos del año (00..99).
%YAño.
%z+hhmm zona horaria.
Ejemplo: -0400.
%:z+hh:mm zona horaria.
Ejemplo: -04:00.
%::z+hh:mm:ss zona horaria.
Ejemplo: -04:00:00.
%:::zZona horaria con precisión.
Ejemplo: -04, +05:30.
%ZZona horaria en formato alfabético.
En este blog podrás encontrar una nueva página que te permite realizar la conversión entre fechas. Podrás cambiar automáticamente entre unixtime a fecha en formato legible y viceversa. Siempre que lo necesites no dudes en emplearlo.

La entrada Formato de fechas en bash la puedes leer en El mundo en bits.
Leer más

Formulario de contacto

Nombre

Correo electrónico *

Mensaje *

Últimos comentarios