lunes, 10 de enero de 2011

Copiando permisos de una BD MySQL a otra

Este script lo encontré en la red y me pareció que debía publicarlo aquí por su gran utilidad:
#!/bin/bash
# adapted from (http://www.pyrosoft.co.uk/blog/2006/10/18/show-grants-for-all-users-on-mysql/)
mysql --batch --skip-column-names -e "SELECT user, host FROM user" mysql |
while read user host; do
  echo "# $user @ $host"
  mysql --batch --skip-column-names -e"SHOW GRANTS FOR '$user'@'$host'"
done

El script mostrado arriba saca todos los usuarios de la BD y luego retorna un script con los privilegios para cada uno de estos, lo que permitiría migrar privilegios y usuarios de una BD MySQL a otra.


martes, 14 de diciembre de 2010

Barajita premiada (#20) - seq con formato

Típico que necesita sacar por consola una secuencia de números, entonces utiliza el comando seq, por ejemplo:
$ seq 1 5 
1
2
3
4
5

O necesita esos números de dos en dos:
$ seq 1 2 5
1
3
5

La cosa se pone interesante cuando requiere formatos, por ejemplo obtener siempre números de dos cifras, entonces puede utilizar:
$ seq -f "%02g" 1 5
01
02
03
04
05

A este punto usted se preguntará, ¿y para qué puede serme útil esto? Pues yo no lo sé, no mentira, esto podría resultar útil para -por ejemplo- filtrar entradas de un log de apache donde cada línea lleva algo como:
192.168.0.1 - - [01/Nov/2010:00:00:33 +0100] "GET ..." 

Si quisiera extraer cada entrada para un día específico podría utilizar un script del tipo:
#!/bin/bash

for day in `seq -f "%02g" 1 31`; do
  count=`egrep -i "\[$day/Nov/[0-9:+ ]+\] \"GET $line" logs/*access.$month.log | grep " 200 " | wc -l`
  echo "$day,$line: $count"
done

¿Y para qué sirvió el seq? para hacer un "for" con valores de dos dígitos y que así tuviera sentido el grep que hacemos dentro del búcle (ver: $day).


martes, 23 de noviembre de 2010

Buscando campos únicos en archivos separados por caracteres (Ej. CSV)

El comando uniq me devuelve, para un conjunto generalmente ordenado previamente (ver: sort), un listado de líneas únicas. Inclusive me puede ayudar a contar el número de coincidencias.

¿El problema? Cuando tengo un archivo con campos separados por caracteres, como un CSV, ¿cómo hago para pedirle sólo únicos para determinados campos del archivo? Pues como Master Card, para todo lo demás AWK ;-)

$ cat a
1|1|2
1|2|3
1|1|5
2|6|7
$ awk -F '|' '!x[$1]++' a
1|1|2
2|6|7
$ awk -F '|' '!x[$1,$2]++' a
1|1|2
1|2|3
2|6|7

Fíjese que para el archivo "a" con campos separados por tuberías "|" extraigo los caracteres únicos, primero considerando el primer campo y luego considerando los primeros dos, Esto no podría hacerse fácilmente con uniq porque tendría que utilizar la vaga y precaria función -skip-chars.


lunes, 25 de octubre de 2010

Transformando un archivo de ids en X para reemplazar en queries del tipo SELECT ... WHERE id IN (X)

Otra útil... típico que tenemos un archivo con un montón de ids y queremos meterlos dentro de alguna query del tipo "WHERE field IN (X)", donde X está formado por todos los ids. Este comando retorna X.

$ awk -v _SQ="'" 'NR>1 { retorno = retorno ", " _SQ $0 _SQ } END { print retorno }' ids 

El archivo ids contiene un id por línea.

* Este ejemplo siempre agrega un id vacio ('') al comienzo, para quitarlo basta agregar un IF. Yo lo he dejado porque me conviene en la mayoría de casos.


Cómo enviar la salida de una query a un archivo separado por "comas" (mysql)

Esta es sencilla pero útil, cómo ejecutar una query y enviar su salida a un archivo separado por comas (o cualquier otro caracter). En PostgreSQL es trivial, pero en MySQL no existe (o al menos no lo he conseguido) un parámetro que defina un FS (field separator).

$ mysql -u root db_name < query | sed 's/\t/|/g' | tee output.csv
Dentro del archivo query está la QUERY. La salida, producto de ejecutar la query, la procesamos con sed reemplazando TABS (\t) por PIPES* (|).

* En lugar de PIPES podrían ser comas, pero no recomiendo ese caracter porque es muy común.

martes, 12 de octubre de 2010

Barajita premiada (#19) - cut & paste

Estos dos comandos son súper útiles cuando deseamos generar archivos CSV a partir de otros CSV. Sobre todo cuando necesitamos pegar columnas con otras (verticalmente). Por ejemplo:

rodolfo@rcampos-laptop:~/cutAndPaste$ cat a 
id|nombre|apellido|nombreCompleto
1|Rodolfo|Campos|Rodolfo Campos
2|Juan|Pérez|Juan Pérez
rodolfo@rcampos-laptop:~/cutAndPaste$ cat b
id|cédula
1|12345678
2|87654321
rodolfo@rcampos-laptop:~/cutAndPaste$ cut -d'|' -f2 b | paste -d '|' a -
id|nombre|apellido|nombreCompleto|cédula
1|Rodolfo|Campos|Rodolfo Campos|12345678
2|Juan|Pérez|Juan Pérez|87654321

En el ejemplo mostrado arriba hacemos lo siguiente:
  1. Cortamos la segunda columna del archivo "b" (opción -f), especificando el delimitador (-d).
  2. Pegamos la salida después del contenido de "a" y la separación de ambos archivos es marcada con un "|" (opción -d). Note que la salida que viene de la tubería (del comando anterior) se especifica como entrada del comando paste utilizando un guión.


Barajita premiada (#18) - sort

Sort, tan "sencillo" pero tan "poderoso".

El comando sort permite ordenar líneas de un flujo de bytes. Este ordenamiento se puede hacer considerando caracteres ASCII, numéricos, binarios, entre otros.

Por ejemplo:
rodolfo@rcampos-laptop:~/sort$ cat a
hello
1
3
44
4
5
foo
rodolfo@rcampos-laptop:~/sort$ sort a
1
3
4
44
5
foo
hello
rodolfo@rcampos-laptop:~/sort$ sort -n a
foo
hello
1
3
4
5
44

En el ejemplo mostrado arriba, el archivo "a" fue ordenado en orden alfabético y luego numérico (opción -n). Para ambos casos, puede observar la diferencia por las posiciones de las palabras y los números 4, 5 y 44.

Pero sort también puede ordenar un archivo con líneas con campos separados por algún caracter (Ej. CSV) rápidamente y sin mayores complicaciones. Esto sobre todo me fue de gran utilidad para ordenar un archivo que pesaba 1Gb y estaba separado por "|". Obviamente debido al tamaño, no resultaba trivial abrir el mismo con Excel y pedirle que ordenara las líneas por la columna X. Mire este ejemplo:

rodolfo@rcampos-laptop:~/sort$ cat a
name|id|type
first|3|1
second|1|1
third|2|2
fourth|0|2
rodolfo@rcampos-laptop:~/sort$ sed '1d' a | sort -t '|' -nk 2
fourth|0|2
second|1|1
third|2|2
first|3|1

En el ejemplo de arriba, es removida la primera línea del archivo con sed (1d) y luego ordenado de forma numérica (-n) considerando el segundo campo (-k 2) para un flujo con campos separados por "|" (opción -t).