Cuando usamos un script en Bash para realizar respaldos de todas las bases de datos MySQL (excepto las de sistema), a veces nos encontramos con el mensaje:
mysqldump: Got error: 1049: "Unknown database 'Database'" when selecting the database
Este error se produce porque, al listar las bases con SHOW DATABASES
, el primer elemento que aparece es el encabezado Database, y si no lo filtramos correctamente, el bucle de respaldo intentará ejecutar mysqldump Database
, provocando el error de “base desconocida”. En este artículo veremos por qué sucede exactamente, y presentaremos dos soluciones sencillas para eliminar esa línea del encabezado y evitar el fallo.
¿Por qué aparece “Database” en la lista de bases?
Supongamos que tenemos un script llamado backupbases.sh
con este fragmento:
#!/bin/bash
# Directorio de trabajo
DIRECTORIO=`pwd`
# Fecha de respaldo
DATE=`date +%Y-%m-%d-%H-%M`
### // Respaldando bases de MySQL \\ ###
# Seleccionar las bases a respaldar (todas menos la palabra Database que aparece al listar las bases)
LIST2=$(mysql -e "show databases" -u root --password=password | awk '{print $1}' | grep -vE '^-|^Database |^information_schema')
# Respaldar cada base y ubicar el respaldo en el directorio actual
for e in $LIST2
do
echo "respaldando $e"
mysqldump $e -u root --password=password -c > $DIRECTORIO/$e-$DATE.mysql
done
### \\ Respaldando bases de MySQL // ###
Cuando corremos mysql -e "show databases"
, la salida normal es:
Database
information_schema
mysql
performance_schema
database1
database2
...
- La primera línea es Database (sin comillas), que actúa como encabezado de columna.
- Luego vienen todas las bases, incluidas las de sistema como
information_schema
yperformance_schema
.
El problema reside en la parte:
… | awk '{print $1}' | grep -vE '^-|^Database |^information_schema'
awk '{print $1}'
extrae la primera columna de cada línea, por lo que produce:Database information_schema mysql performance_schema database1 database2 ...
- El patrón
^Database
(con un espacio después de “Database”) no coincide con la líneaDatabase
(que no tiene un espacio al final). Por tanto, “Database” no se filtra, y queda en la variable$LIST2
. - Al iterar sobre
$LIST2
, el bucle ejecuta primeromysqldump Database -u root ...
, y MySQL devuelve:Got error: 1049: "Unknown database 'Database'" when selecting the database
Para eliminar este encabezado de manera correcta, podemos usar dos estrategias principales.
Opción 1: usar --skip-column-names
al listar bases
MySQL permite omitir la fila de encabezado en la salida de consultas usando la opción --skip-column-names
(o su forma corta -N
). De este modo, el comando
mysql -u root --password=password --skip-column-names -e "SHOW DATABASES;"
devuelve directamente:
information_schema
mysql
performance_schema
database1
database2
...
sin la línea “Database” al inicio. Luego solo tenemos que filtrar las bases de sistema que no queremos respaldar, por ejemplo:
#!/bin/bash
# Directorio de trabajo
DIRECTORIO="$(pwd)"
# Fecha de respaldo (AAAA-MM-DD-HH-MM)
DATE="$(date +%Y-%m-%d-%H-%M)"
### // Respaldando bases de MySQL \\ ###
# Listar bases (sin cabecera) y excluir sólo information_schema y performance_schema
LIST2=$(
mysql -u root --password=password \
--skip-column-names \
-e "SHOW DATABASES;" \
| grep -Ev '^(information_schema|performance_schema)$'
)
# Respaldar cada base y guardar el archivo en el directorio actual
for e in $LIST2; do
echo "respaldando $e"
mysqldump -u root --password=password -c "$e" \
> "$DIRECTORIO/$e-$DATE.mysql"
done
### \\ Respaldando bases de MySQL // ###
¿Qué hace este script?
--skip-column-names
quita el encabezado “Database”.grep -Ev '^(information_schema|performance_schema)$'
elimina exactamente las dos bases de sistema que no queremos respaldar.- El bucle
for e in $LIST2
recorre únicamente los nombres de bases válidos (por ejemplo,mysql
,database1
,database2
, …). - Para cada base, se ejecuta
mysqldump
y se genera un archivo con nombre<base>-<fecha>.mysql
.
Con esto, ya no aparece la línea “Database” en $LIST2
, y por ende desaparece el error 1049.
Opción 2: filtrar “Database” exacto con una expresión regular
Si prefieres no usar la opción --skip-column-names
, basta con corregir el patrón de grep
para que descarte la línea que es exactamente “Database” (sin espacios extra). Para ello, cambiamos el grep -vE '^-|^Database |^information_schema'
por:
grep -Ev '^(Database|information_schema|performance_schema)$'
El script completo quedaría así:
#!/bin/bash
# Directorio de trabajo
DIRECTORIO="$(pwd)"
# Fecha de respaldo (AAAA-MM-DD-HH-MM)
DATE="$(date +%Y-%m-%d-%H-%M)"
### // Respaldando bases de MySQL \\ ###
# Listar bases (con encabezado) y filtrar para evitar "Database", "information_schema" y "performance_schema"
LIST2=$(
mysql -u root --password=password -e "SHOW DATABASES;" \
| awk '{print $1}' \
| grep -Ev '^(Database|information_schema|performance_schema)$'
)
# Respaldar cada base válida
for e in $LIST2; do
echo "respaldando $e"
mysqldump -u root --password=password -c "$e" \
> "$DIRECTORIO/$e-$DATE.mysql"
done
### \\ Respaldando bases de MySQL // ###
Por qué funciona
awk '{print $1}'
sigue sacando la primera columna, incluidos “Database” e “information_schema”.grep -Ev '^(Database|information_schema|performance_schema)$'
:^…$
obliga a que coincida toda la línea completa.(Database|information_schema|performance_schema)
descarta exactamente esas tres entradas.
- De esta forma, “Database” ya no está en la lista
$LIST2
.
Buenas prácticas adicionales
Más allá de eliminar el encabezado “Database”, conviene seguir estos consejos al crear scripts de respaldo:
- Separar credenciales
Evita poner la contraseña en texto claro dentro del script. En su lugar, crea un archivo~/.my.cnf
con contenido similar a:[client] user=root password=TU_CONTRASEÑA
Y ajusta el script para usar simplementemysql
ymysqldump
sin-u root --password=…
. - Excluir otras bases de sistema
Además deinformation_schema
yperformance_schema
, podrías querer excluirmysql
(dependiendo de si quieres respaldar los privilegios) osys
. Ajusta elgrep -Ev '…'
para incluirlas en caso de no necesitar un backup de esas bases. - Almacenamiento separado por fecha
En lugar de guardar todos los.mysql
en el mismo directorio, podrías crear una subcarpeta con la fecha del día:DIR_RESPALDO="$DIRECTORIO/respaldos/$(date +%Y-%m-%d)" mkdir -p "$DIR_RESPALDO" … > "$DIR_RESPALDO/$e-$DATE.mysql"
Así tendrás ordenados los respaldos por día. - Manejo de errores
Captura el código de salida demysqldump
para detectar fallos y, si uno ocurre, notifica por correo o detén el script:if ! mysqldump -u root --password="$PASSWORD" -c "$e" > "$ARCHIVO"; then echo "Error: no se pudo respaldar $e" >&2 exit 1 fi
- Programar con cron
Para automatizar el respaldo diario, añade una entrada en el crontab del usuario:0 2 * * * /ruta/a/backupbases.sh >> /ruta/a/log_backupbases.log 2>&1
Esto ejecuta el script cada día a las 2 AM y redirige la salida a un archivo de log.
Conclusión
El error:
mysqldump: Got error: 1049: "Unknown database 'Database'" when selecting the database
se debe a que el encabezado literal Database que MySQL imprime al listar bases no se estaba filtrando correctamente, quedando en la lista de $LIST2
. Para evitarlo, puedes:
- Opción 1: usar
mysql --skip-column-names -e "SHOW DATABASES;"
y luego filtrar solo las bases de sistema que no deseas respaldar. - Opción 2: mantener la salida con encabezado y ajustar
grep -vE
para excluir exactamente la líneaDatabase
, junto coninformation_schema
yperformance_schema
.
Ambas soluciones impiden que el bucle intente respaldar una base llamada “Database” y, por tanto, evitan el error 1049. Elige la que mejor se adapte a tu entorno y, de paso, considera implementar buenas prácticas como separar las credenciales, organizar los backups por carpetas y manejar errores dentro del script. ¡Así tendrás un respaldo confiable y libre de fallos!