Bash

Aspectos básicos

“Depurar” código bash

Lo más directo es habilitar las trazas mediante el parámetro -x de bash (equivalente a la opción xtrace). Se puede refinar definiendo algunas variables:

# xtrace -> imprimir trazas
set -o xtrace
# version abreviada de la linea anterior
set -x
# noglob -> impedir el procesamiento de metacaracteres en nombres de fichero ("globbing")
set -o noglob
set -f  
# verbose -> imprimir las líneas de código según se van leyendo
set -o verbose 
set -v  
# nounset -> abortar al intentar usar una variable no definida
set -o nounset
set -u
# cambiando la variable PS4 se puede personalizar las trazas. Por ejemplo, añadir el número de línea
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

Variables

Valores por defecto: con “:-” se asigna el valor a la variable. Con “:=” simplemente se retorna el valor por defecto (cuando la variable no tiene valor), esto es, no se modifica la variable.

login="pepe"
export login="pepe"
echo ${login}
echo ${login:=login no definido}
echo ${login:-invitado}

Cadenas

linea="tres tristes"
linea+=" tigres"
echo ${linea}

# Subcadenas
${linea:posicion:longitud}
${linea: -posicion:longitud} # ojo al espacio antes de "-", es importante

# Eliminar subcadenas
f="/usr/lib/libkewl.so" 
# borrar por el principio
${linea#*/}  # elimina la subcadena de menor longitud, comenzando por el principio
${linea##*/} # elimina la subcadena de mayor longitud
# borrar por el final
${linea%/*}  # elimina la subcadena de menor longitud, comenzando por el final
${linea%/*}  # elimina la subcadena de mayor longitud, comenzando por el final

# Sustitucion
${linea/patron/sustitucion} # primera aparicion
${linea//patron/sustitucion} # todas apariciones

# Longitud cadena
${#string}
expr length $string

# tests con cadenas
# cadena vacia / no vacia
[ -z "${s1}" ]  # cadena vacia
[ -n "${s2}" ]  # cadena no vacia

# Pertenencia
[[ "${linea}" == *tristes* ] ]

# Split / join
# usando sustitución
readonly DIR_SEP="/"
array=(${f//${DIR_SEP}/ })
second_dir="${array[1]}"
# usando IFS
hora="HH:MM:SS"
IFS=":" read -ra campos <<< "${hora}" 
# Para agrupar palabras en una linea (por ejemplo, con nombres que incluyen espacios), cambiar el separador IFS a \n (escapandolo con $):
IFS=$'\n'

Control de flujo

Condiciones: dentro de [ ] para seguir el estándar POSIX (“clásico”). Para usar las bondades de la extensión del estándar, meter la condición dentro de [[ ]].

También se puede comparar directamente el código de retorno (sin corchetes)

Operadores “clásicos”:

  • ==, != comparacion cadenas, -z longitud cero, -n longitud no cero
  • -f fichero, -d directorio, -r lectura, -w escritura, -x ejecutable
  • -eq -gt -lt -ne -ge -le: comparacion numerica

Operadores de la extensión del estándar:

  • =~ expresiones regulares
if [ cond ]; then
        b1
elif [[ "${linea}" == *tristes* ] ]; then
        b2
elif grep -qF "string" file; then
    echo 'file contains "string"'
else
        b3
fi

for x in SECUENCIA; do
   echo $x
done

case PATTERN in
        p1)
        ;;
...
        pm)
        ;;
        *)
        ;;
esac

Aritmética

Tradicionalmente se hacían con expr o bc, pero hoy en día suele ser más práctico usar los “dobles paréntesis”:

(( a ++ ))
(( x = a>3?1:0 ))

# si queremos hacer la asignación fuera de los dobles paréntesis,
# hay que añadir un dolar:
Z=$(( x + 4 ))

# número aleatorio
x=$RANDOM

# módulo
let "x %= 100"

Límites numéricos de bash (ver también los límites de awk)

Vectores (arrays)

Empiezan en 0

#operaciones basicas
a[3]=X
echo ${a[3]}
# longitud
${#arrayname[@]}
# se puede crear un array facilmente con ():
a=(1 2 3 4)

Se puede asignar tal cual una “lista” separada por espacios:
declare -a nombres
nombres=(paco pablo pato)

Esto se puede combinar con la sintaxis “salida de un comando”, $(), para llegar al combo ($( )):

nombres=($(ls))

Patrón “lista de directorios”

for d in $(ls -d */); do
...
done

Patrón “glob” (operar recursivamente partiendo de un directorio)

find d -exec cmd1 {} \; -exec cmd2 {} \;

Patrón “fichero de configuración”

En bash, es preferible escribir el fichero de configuración en bash y “cargarlo” con source (o su abreviatura, “.”), a usar otra sintaxis y tener que parsearlo como texto…

Patrón “procesamiento de patrones”

Con el operador =~ es bastante simple:

# para no tener que escapar la expresion regular, lo mejor es meterla en una variable
my_regex="([[:alpha:][:blank:]]*)- ([[:digit:]]*) - (.*)$"

if [[ "$CDTRACK" =~ ${my_regex} ]]; then
        echo Track ${BASH_REMATCH[2]} is ${BASH_REMATCH[3]}
        mv "$CDTRACK" "Track${BASH_REMATCH[2]}"
fi

# BASH_REMATCH contiene los emparejamientos de la ultima expresion regular

Patrón “diccionario”

Los diccionarios se conocen en bash como “arrays asociativos”

# -A -> array asociativo
declare -A rutas
rutas[pepe]="/users/g1/pepe"
clave="pepe"
echo ${rutas[${clave}]}
rutas=([marcos]="/users/g1/marcos")
rutas+=([lucas]="/users/g3/lucas")
# asignación múltiple
rutas([pedro]="/users/g2/pedro" [antonio]="/users/g1/antonio")
# clave con espacios
rutas["jose luis"]="/users/tic/jl"
echo ${rutas[antonio]}
ruta=${rutas[antonio]}
# todos los valores
echo ${rutas[@]}
# todas las claves
echo ${!rutas[@]}

# patrón "imprimir diccionario"
for usuario in "${!rutas[@]}"; do
    echo "${usuario} ${rutas[$user]}"
done

Redirecciones

Redirección básica: salida (“>”), entrada (“<") Añadir: ">>”

“Triple redireccion”: pasa una cadena por la entrada estándar

echo 1234X-D | sudo joe -c “passwd”
sudo joe -c “passwd <<< 1234X-D" Usar procesos en vez de ficheros (Process substitution) Con <() se conecta la entrada estándar de un comando con la salida estándar de los comandos dentro de los paréntesis. Sustitución de comando por su salida: [code] # clasica FILES=`ls` # contemporanea en linea. Ventajas: se pueden anidar varias FILES=$(ls) # contemporanea a array (Asignar el resultado a un array) FILES=($(ls)) [/code] # Añadir una cabecera a una lista para que column formatee la cabecera y la lista column -t <(echo "Permisos i user group count fecha hora nombre") <(ls -l | sed 1d) # Opciones: >() o <() (sin espacio entre el < o el > y los parentesis)
comm <(ls -l) <(ls -al)

“Punteros”

p=x
x=2
# Imprime x
echo $p
eval p=\$$p
# Imprime 2
echo $a

Paralelismo

El clasico “&” y los coprocesos (coproc)

Expresiones estilo C

# Solo operacion (no se usa el valor de retorno)
(( a = 20 )) # mantener todos los espacios
(( a ++ ))
(( x = a>3?1:0 ))
echo $x # imprime 1
# Para valor de retorno hay que añadir $
Z=$(( x + 4 ))

Patrón “procesar parámetros”

* Procesar parametros del script con getopts
# El primer parametro es la lista de switches que se aceptan, un “:” despues de una letra indica que ese
# switch acepta un parametro, por ejemplo -b hola
while getopts “:ab:cd” Option
do
case $Option in
b) echo “b” parameter is $OPTARG

esac
done

* Secuencias de números
for i in `seq 1 20`…
for i in {1..20}…
# Con ceros delante
for i in `seq -f %03.0f 1 10`…
for i in `printf ‘%03d ‘ {0..123}`…

Proceso de texto

Leer líneas

Bash FAQ 001

read / mapfile / readarray

cat fichero | while read -r linea; do
   echo "${linea}"
done
# fuera del bucle, la variable linea no está accesible
echo ${linea}

# readarray funciona como un alias de mapfile
declare -a lineas
mapfile lineas < fichero
echo ${lineas[1]}

En ambos casos, ojo con las subshells

Patrón “leer columnas”

# con read
# ojo: como las tuberías crean subshells, 
# no se puede acceder desde fuera del bucle a las variables leidas...
cat fichero | while read C1 C2 C3; do
   echo $C2
done

Declarando una variable como array, es “facil” sacar los campos de una linea en bash:

declare -a TEST
TEST=(a b c d)
echo ${TEST[0]}
# a
TEST=(1 b c d)
echo ${TEST[0]}
# 1
# Con triple redireccion:
read C1 C2 <<< "Campo1 Campo2"
# O bien, usar la redireccion simple, en lugar de un pipe:
while read C1 C2; do .... done < fichero

Curiosidades

Hidden features of bash

Mis favoritas:

  • Alt + . (último parámetro)
  • ${SECONDS}
  • ${RANDOM}
  • TMOUT

Operaciones con conjuntos en shell

Bash one-liners

Página principal GNU Bash

Bash hackers Wiki

Bash FAQ (en “Greycat’s Wiki”)

Documentación sobre Bash en StackOverflow Documentation

sed

Expresiones regulares en sed: para usarlos como metacaracteres, hay que “escapar” +, (, ), ?

“ak* \+xx\?” -> “akkk xx3”

Sustitución reutilizando el patron

# Caso sencillo: 1 solo patron. Se puede usar &:
# Añadir parantesis a cada secuencia de numeros
sed 's/[0-9]*/(&)/'

# Para varios patrones, se marcan los patrones a reutilizar con parentesis,
# y se utiliza \1, \2 para referenciar cada patron encontrado:
# Intercambiar el primer campo con el segundo. Por ejemplo, Type: abc-123 se convierte en Type: 123-abc
sed 's/Type: \([a-z]*\)-\([0-9]*\)/Type: \2 \1/'
# Elimina el path de una url, dejando solo hasta el hostname
sed "s_\(http://[a-z0-9A-Z.\-]*/\)\(.*\)_\1_"

Extraer cadenas de una linea

Con egrep (grep -E) se puede imprimir la parte de una linea que coincida con un patron.

Por ejemplo, para extraer las temperaturas de una linea…

echo "Temp1: 37.2 C Temp2: 40.0 C" | grep -Eo '[0-9\.]+[[:punct:]]?[ ]?[CF]+'

Inserción de texto

# Añadir texto al final de una linea
sed '/^wheel/ s_$_,newWheelUser_' /etc/group

Con i inserta un texto antes de la linea actual, con a despues. En ambos casos introduce un salto de linea. Por eso, para que inserte en la misma linea hay que recurrir a la sustitucion:

> sed iabcd
  fge
  abcd
  fge
> sed aabcd
  geg
  geg
  abcd
> sed s/^/abcd/g
   geg
   abcdgeg

# Añadir una linea al final de varios ficheros de texto
sed -i '$aexit 0' *
# Añadirla al principio (con salto de línea 😉
sed -i '1i. /home/group-bashrc\n' /home/*/.bashrc

Para ejecutar varios comandos sed en una línea, separar con “;”

sed "s/NODE/$NODE/g;s/IP/$IP/g" < $TEMPLATE

UNIX Stream EDitor (sed) Cheat Sheet

Decepcionante Macworld Expo 09

Por lo que respecta a Apple, ada realmente nuevo, salvo la ausencia de Steve Jobs por sus problemas hormonales.

En hardware un Macbook de 17″ potentillo y con batería de larga duración, lo cual es interesante a priori.

Pero la batería va integrada en el portátil, estilo iPod. O sea, reza para que no se te estropee la batería y mantenga su autonomía durante muchos años.

Durante mucho tiempo esta Expo fue un evento, con presentaciones como los Mac Intel en 2006, o el iPhone del 2007. El futuro pinta oscuro con el anuncio de Apple de que no volverá a participar en esta feria.

Curiosamente, Palm despierta algo de interés con otro competidor de iPhone: el Palm Pre.

Reinstalar grub a mano

Puede ocurrir que perdamos el arranque de grub (por ejemplo, al instalar Windows después de Linux). Algunas distribuciones incluyen entre las opciones de sus discos de instalación la opción “rescate” (Rescue), dentro de la cual puede aparecer la recuperación automática de Grub.

Arrancando desde un Live CD, también se puede reinstalar grub “manualmente”:

  1. Montar la partición raíz (por ejemplo, en /mnt/linux)
  2. Ligar los sistemas de ficheros /dev, /proc y /sys dentro de /mnt/linux (usando “mount -o bind”)
  3. “Teletransportarnos” a /mnt/linux con “chroot /mnt/linux” (una de las múltiples chuladas de Linux ^_^)
  4. Instalar grub: “grub-install /dev/sda” (suponiendo que ese sea el disco duro en el cual queremos instalarlo)

Excel 2008

La última versión de Excel para Mac tiene envidia de su rival Numbers, así que ahora luce más bonito (en la línea Apple).

El lucimiento se extiende a las gráficas, que ahora por defecto son más aparentes. El problema es que en algunos puntos se han pasado de “filosofía Apple”.

Ejemplo: en las clásicas gráficas de barras, ahora no se pueden personalizar las etiquetas del eje X. Hay que conformarse con lo que el propio Excel crea que es bueno. Así, si queremos que en esas etiquetas aparezcan unos números en particular, hay que “engañar” al Excel para que crea que son texto (y no basta con especificar que el formato de las celdas es texto). Hay que escribir texto: en lugar de “3”, poner “3 segundos para volver a Office 2004”.

Si Excel considera que las celdas son texto de verdad, se puede proceder como tradicionalmente: seleccionar las 2 columnas a representar y elegir el tipo de gráfica de barras. Una vez hecho, el texto aparecerá abajo como etiquetas del eje X y la otra columna serán los valores de las barras.

Otro cambio estético que impacta la usabilidad son las leyendas. Ahora están en la paleta flotante, sección Opciones de gráfica / Títulos.

iPod

El iPod (recientemente renombrado como “iPod Classic”) es un juguete codiciado, aunque a primera vista pueda parecer un reproductor del montón con un bonito diseño. Hasta que no se posee uno es difícil percatarse de esos pequeños detalles que lo hacen un gran reproductor por el que pagar una pasta.

Algunas virtudes del iPod:

  • interfaz cómodo y sencillo, resultado de la sabia combinación de la rueda con los menús. O recientemente, una gran pantalla táctil y el Multitouch
  • capacidades para todos los gustos, desde 1 GB para la gran mayoría hasta los 160 GB para melómanos empedernidos
  • reproducción auténticamente sin interrupciones (gapless), siempre que los ficheros estén preparados (un CD convertido a AAC, por ejemplo)
  • listas “inteligentes”
  • posibilidad de puntuar fácilmente las canciones
  • el diseño. Por ejemplo, la ubicación de la entrada para auriculares
  • la integración con iTunes simplifica la gestión de una colección de música amplia
  • recuperación automática de las carátulas de los discos (necesita cuenta en el Apple Store)

Algunos inconvenientes:

  • el precio, aún más excesivo si tenemos en cuenta que la caja del iPod sólo contiene el iPod y unos auriculares normales y corrientes. El cargador (para no depender de un puerto USB) va aparte a precio elevado.
  • el soporte. Échate a temblar si tu iPod comienza a fallar (no se te ocurra acercarle un imán), si la batería dura 5 minutos… La única solución práctica al 90% de este tipo de problemas es comprarse un iPod nuevo…
  • la salida de línea va integrada en el conector de la base y no hay muchos cables compatibles
  • la forma sencilla de pasar las canciones al iPod es iTunes, el cual ata de varias formas:
    • iTunes no deja descargar la música del iPod al ordenador
    • el iPod se vincula con el primer iTunes que lo sincroniza, de modo que no se puede hacer sincronización automática con otros iTunes (de otros usuarios o en otros ordenadores). Lo cual significa que si tienes la mala suerte de perder los datos de tu biblioteca iTunes, vas a tener que sincronizar tu iPod de nuevo desde cero. Es decir, a pasar otra vez todos los ficheros, a volver a crear las listas de reproducción y a volver a calificar tus canciones favoritas
    • Por suerte, hay programas como SharePod que permiten recuperar las canciones en caso de que no se pueda acceder a los originales en el ordenador

Pon un control de versiones en tu vida!

Sorprendentemente los sistemas de control de versiones siguen siendo los grandes desconocidos, y por tanto, los grandes ignorados. A pesar de que su utilidad es indiscutible…

El desconocimiento puede llevar a pensar que son muy complejos o difíciles de usar. Nada más lejos de la realidad. Para proyectos “personales” sólo se necesita RCS y un comando:

ci -l

En la hora en que uno se encuentra entre la espada y la pared, puede ser de gran ayuda este otro comando:

co -r

“ci -l” guarda una nueva versión del fichero manteniendo una copia bloqueada a disposición de nuestro editor de textos favorito. “co -r” extrae la versión del fichero que deseemos, con lo que podemos volver fácilmente al momento en que el programa compilaba perfectamente (e incluso funcionaba…)

Cuando colaboran varios suele compensar la creación de un repositorio centralizado. Para ello se puede recurrir a subversion, gratuito e integrable en la mayoría de entornos de desarrollo (como Netbeans o Eclipse)

Windows en Mac

Tras el cambio a procesadores Intel, Apple ha ensanchado sus horizontes con Boot Camp. Esta herramienta simplifica considerablemente la instalación nativa de Windows XP (Service Pack 2 o posterior) y Windows Vista en los ordenadores Mac.

La última versión incluye controladores para casi todos los dispositivos de los Mac. Por ejemplo, el iSight, el Airport y el Bluetooth de los últimos MacBook. Gracias a ello se puede disfrutar (o sufrir) plenamente de Windows en los ordenadores de Apple.

Boot Camp vendrá de serie en el próximo OS X (10.5 o Leopard)

También se puede emular Windows dentro del OS X con soluciones comerciales como VMWare o Parallels Desktop, o gratuitas como QEmu (aunque esta última opción no funciona tan bien como las otras)

Resolución de problemas de autenticación

ssh permite identificarse en un servidor remoto sin introducir una clave. Para ello basta con añadir nuestra clave pública en el fichero ~/.ssh/authorized_keys

ssh intenta ser precavido, con lo cual esta forma de identificación sólo funciona (por defecto) si sólo el usuario tiene posibilidad de escribir en su “home”. Con el sistema de permisos clásico de Unix/Linux, el usuario debe ser propietario de su home, y el permiso de escritura sólo puede estar habilitado para él (el típico patrón “755”)

Obviamente, el fichero de claves autorizadas tiene que ser correcto sintácticamente. A veces no es el caso, cuando uno “copia y pega” su clave y se cuela algún imperceptible salto de línea o espacio.

Además, la configuración del demonio SSH debe permitir el acceso con clave pública a ese usuario en particular. A veces no es el caso, bien porque el usuario es root y en la configuración se especifica “PermitRootLogin no”, o bien porque se declara “RSAAuthentication no” o “PubkeyAuthentication no”.

Para saber mas…

http://sial.org/howto/openssh/publickey-auth/problems/