Esta tarde he recibido un email de OVH diciendo que me quedaba una semana para que mi alojamiento compartido se terminara. Como a pesar de que me queje (porque un fin de semana sin server es apocalíptico), no me han dado muchos problemas este año, he decidido renovar con ellos, cambiando mi antiguo “plan90″ (ahora ya no existe con ese nombre) por otro “profesional” que me venía mucho mejor (necesitaba una buena BD MySQL, bastante espacio y mucho tráfico mensual) y portando todo al nuevo servidor.
El caso es que la base de datos de nuestra aplicación “estrella” de Facebook es bastante inmanejable para un PHPMyAdmin, son 117 MB de backup. En una supertabla con millones de entradas teníamos un par de campos que no se usaban, y que ocupaban una burrada, no por su longitud sino por el número de instancias. Después de tratar unas cuantas veces de borrarlos por SSH, usando el comando “mysql”, y desde la interfaz web sin resultados me he puesto a buscar la mejor manera de modificar el script de backup.
Resulta que teníamos varios millones de inserciones del estilo “INSERT INTO usuario VALUES (’121900349302′, 13, 44, 27);”, donde los dos últimos número sobraban porque eran los valores de los campos que no quería usar más. El primero de los dos podía recibir un NULL, y el segundo valores negativos. Y aquí entra “sed“:
El comando sigue la estructura “sed [opciones] instrucciones [fichero]“. Si no se especifica un fichero lee de la entrada estándar (así que se le pueden pasar valores con un pipeline | ). Las instrucciones deben ir entre comillas simples, para que el comando no trate de explotar símbolos como * o $. Si son de sustitución deben empezar por s y seguir este formato: ‘s/VIEJA/NUEVA/’
Por ejemplo:
echo "Vivo en: C/ Fuencarral" | sed 's/C\//la calle/'
Daría como resultado:
Vivo en: la calle Fuencarral
Como podéis ver he escapado la barra / con otra barra inversa delante \. VIEJA acepta patrones (otro día hablare de ellos), y el “juego de metacaracteres extendido” (para poder usar patrones con: *, ?, +, [ - ], {,}, etc) si usamos la opción -E, por ejemplo:
echo "Vivo en: C/ Fuencarral" | sed -E 's/[a-zA-Z]{5,10}/Gran Vía/g'
Tiene por salida:
Vivo en: C/ Gran VíaEn el ejemplo le he dicho que sustituya todas las cadenas formadas por letras mayúsculas o minúsculas de entre 5 y 10 caracteres por “Gran Vía”, por lo que ha sustituido “Fuencarral”. He añadido además una g después de la última barra, que significa que no se pare en la primera que encuentre, que sustituya hasta el final.
Es posible también aplicar varias instrucciones seguidas separadas por punto y coma, de esta forma:
sed 's/a/A; s/b/B' fichero_a_modificar.txt
o separándolas con la opción -e:
sed -e 's/a/A' -e 's/b/B' fichero_a_modificar.txt
También es posible que decirle que coja las instrucciones de un fichero con la opción -f seguida del nombre:
sed -f reglas.sed fichero_a_modificar.txt
Y evitar que muestre el resultado por pantalla con -n:
sed -n 's/b/B' fichero_a_modificar.txt
Mi problema con las tablas se ha solucionado con:
sed -E 's/, (NULL|[0-9]+), -?[0-9]+\)/)/g' backup.sql > backup_limpio.sql
Que sobre un fichero que contenga:
INSERT INTO usuario VALUES ('121900349302', 13, NULL, -27); INSERT INTO usuario VALUES ('121900349303', 13, 43, 37); INSERT INTO usuario VALUES ('121900349304', 13, NULL, -18); INSERT INTO usuario VALUES ('121900349305', 13, 45, 9);
Obtiene:
INSERT INTO usuario VALUES ('121900349302', 13); INSERT INTO usuario VALUES ('121900349303', 13); INSERT INTO usuario VALUES ('121900349304', 13); INSERT INTO usuario VALUES ('121900349305', 13);
¡Si alguien encuentra algo interesante sobre “sed” o patrones que lo comente!

Pingback: URLs bonitas modificando .htaccess | TecnoCaos
tengo una duda muy simple , si quiero hacer
echo $HOME
/home/user_name
como hago que sed borre “/home/” ??? me gustaria que el resultado fuera
asignado a una varibale.
prueba con “echo $USER”
Tengo un archivo con datos agrupados en una cantidad variable de lineas consecutivas y separados entre ellos por uno o dos espacios en blanco del tipo:
gonzalez
antonio gonzalez izquierdo
c/ buendia 12
madrid
rodriguez
jose rodriguez gomez
informatico de cuidado
un buen elemento
c/ norte 23
segovia
gutierrez
cuesta de arriba 27
ciudad real
Quisiera enviar cada grupo de datos de este documento a un archivo. En el ejemplo que he puesto tendría que dar como resultado 3 ficheros: uno con los datos de gonzalez, otro con los datos de rodriguez y el último con los de gutierrez.
Estoy batallando con sed y awk pero mis conocimientos de bash scripting son más bien escasos. ¿Puedes echarme una mano?