Como executar um comando MySQL a partir de um shell script?

131

Como posso executar um comando SQL através de um shell script para que eu possa automatizá-lo?

Eu quero restaurar os dados que eu coletei em um arquivo SQL usando um script de shell. Quero me conectar a um servidor e restaurar dados. O comando funciona quando executado separadamente via linha de comando SSH.

Este é o comando que eu uso:

mysql -h "server-name" -u root "password" "database-name" < "filename.sql"

Este é o código do script shell que cria o arquivo ds_fbids.sqle o envia para o mysql.

perl fb_apps_frm_fb.pl
perl fb_new_spider.pl ds_fbids.txt ds_fbids.sql
mysql -h dbservername -u username -ppassword dbname < ds_fbids.sql

Qual é a maneira correta de fazer isso?

MUFC
fonte

Respostas:

176

Você precisa usar a -pbandeira para enviar uma senha. E é complicado porque você não deve ter espaço entre -pe a senha.

$ mysql -h "server-name" -u "root" "-pXXXXXXXX" "database-name" < "filename.sql"

Se você usar um espaço depois -pque o cliente mysql solicitar a senha de forma interativa, você interpretará o próximo argumento de comando como um nome de banco de dados:

$ mysql -h "server-name" -u "root" -p "XXXXXXXX" "database-name" < "filename.sql"
Enter password: <you type it in here>
ERROR 1049 (42000): Unknown database 'XXXXXXXX'

Na verdade, prefiro armazenar o usuário e a senha em ~ / .my.cnf, para não precisar colocá-lo na linha de comando:

[client]
user = root
password = XXXXXXXX

Então:

$ mysql -h "server-name" "database-name" < "filename.sql"

Re seu comentário:

Eu executo comandos mysql em modo de lote como o acima na linha de comando e em scripts de shell o tempo todo. É difícil diagnosticar o que há de errado com o seu script de shell, porque você não compartilhou o script exato ou qualquer saída de erro. Sugiro que você edite sua pergunta original acima e forneça exemplos do que está errado.

Além disso, quando estou solucionando problemas de um script de shell, uso o -xsinalizador para ver como ele está executando cada comando:

$ bash -x myscript.sh
Bill Karwin
fonte
Obrigado por uma resposta rápida. Eu cansei colocando a senha na própria linha de comando. O verdadeiro problema é que eu estou colocando esse comando no arquivo .sh e executando esse script de shell. O comando no arquivo não é executado na linha de comando, mas o mesmo comando funciona perfeitamente quando executo apenas o comando na linha de comando.
MUFC
+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:Esta é a mensagem de erro que recebi
MUFC 8/11
Ok, eu inferiria que seu diretório de trabalho atual não é onde o arquivo ids.sql está localizado. Além disso, você pode incorporar novas linhas em seu script.
Bill Karwin
Eu tenho novas linhas incorporadas no meu shell script após cada comando. Tudo o que meu script de shell contém são 3 comandos de linha de comando que eu não quero executar separadamente, então eu criei um script de shell para fazê-los rodar sem a minha intervenção e coloquei uma nova linha após cada comando. Isso está causando problemas?
MUFC
melhor evitar -pse a senha for nula ou vazia, talvez você possa atualizar sua postagem? :)
James Oravec
118

Use esta sintaxe:

mysql -u $user -p$passsword -Bse "command1;command2;....;commandn"
Kshitij Sood
fonte
8
Cheguei a esta página no google e esta é a solução que eu esperava (correspondente ao título da pergunta).
Janaka R Rajapaksha 01/01
15
Mais alguns detalhes sobre as opções do manual: -B é para lote, imprima os resultados usando a guia como separador de colunas, com cada linha em uma nova linha. Com esta opção, o mysql não usa o arquivo de histórico. O modo de lote resulta em formato de saída nãoabular e escape de caracteres especiais. -s é o modo silencioso. Produza menos produção. -e é para executar a instrução e sair
wranvaud
Obrigado pela ajuda! :)
haotang
Poderia ser executado com um heredoc?
Zx1986
1
@ zx1986 Sim e Não, para o HEREDOC. Depende de como você pretende usá-lo. Usá-lo para substituir a "command1;command2;....;commandn"parte desta resposta não funcionará. Usá-lo para substituir o uso do arquivo redirecionado na sintaxe do OP pode funcionar. Eu resolvi esse problema na minha resposta a esta pergunta.
Chindraba 19/01/19
45

Todas as respostas anteriores são ótimas. Se for um comando sql simples de uma linha que você deseja executar, também poderá usar a opção -e.

mysql -h <host> -u<user> -p<password> database -e \
  "SELECT * FROM blah WHERE foo='bar';"
Jericon
fonte
Consulta entre aspas duplas ("") foi o que eu preciso fazer. Graças
user3132107
Entendo, e acredito que você precisa incluir o ponto e vírgula no final da consulta?
Lori
19

Como executar um script SQL, use esta sintaxe:

mysql --host= localhost --user=root --password=xxxxxx  -e "source dbscript.sql"

Se você usa o host como host local, não precisa mencioná-lo. Você pode usar isto:

mysql --user=root --password=xxxxxx  -e "source dbscript.sql"

Isso deve funcionar para Windows e Linux.

Se o conteúdo da senha contiver um !(ponto de exclamação), você deverá adicionar um \(barra invertida) na frente dele.

Milinda Bandara
fonte
1
Como especificar o banco de dados? deveria estar dentro de -e, como -e "use abc; source dbscript.sql"?
Abdul Muneer
9

O núcleo da pergunta já foi respondido várias vezes, apenas pensei em acrescentar que os backticks (`s) dependem tanto do script de shell quanto do SQL. Se você precisar usá-los no SQL para especificar um nome de tabela ou banco de dados, precisará escapá-los no shell script da seguinte maneira:

mysql -p=password -u "root" -Bse "CREATE DATABASE \`${1}_database\`;
CREATE USER '$1'@'%' IDENTIFIED BY '$2';
GRANT ALL PRIVILEGES ON `${1}_database`.* TO '$1'@'%' WITH GRANT OPTION;"

É claro que a geração de SQL por meio de entradas concatenadas do usuário (argumentos passados) não deve ser feita, a menos que você confie na entrada do usuário. no MySQL.

Li1t
fonte
5
mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file

(use o caminho completo para, sql_script_filese necessário)

Se você deseja redirecionar a saída para um arquivo

mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file > out_file
videira
fonte
@ Gus, em primeiro lugar obrigado pelos valiosos comentários. Funcionou como um encanto para mim. Quero que a saída seja um arquivo excel ou .csv. como posso conseguir isso. Desde já, obrigado.
Ash_and_Perl
@Ash_and_Perl Eu apenas editei esta resposta, graças a você, não a mim, é a resposta dele. Se você já tiver uma pergunta e já tiver tentado encontrar uma solução , sugiro que você crie uma pergunta. Dessa forma, você pode detalhar o que tentou, como falhou, e as pessoas podem fornecer uma resposta completa e completa (e obter pontos por isso!).
Gus
5

Você esqueceu -pou --password=(o último é melhor legível):

mysql -h "$server_name" "--user=$user" "--password=$password" "--database=$database_name" < "filename.sql"

(As aspas são desnecessárias se você tiver certeza de que suas credenciais / nomes não contêm espaço ou caracteres especiais do shell.)

Observe que a página de manual também diz que fornecer as credenciais na linha de comando é inseguro. Então, siga os conselhos de Bill sobre my.cnf.

Orelhas pontudas
fonte
4

Conforme declarado antes, você pode usar -p para passar a senha para o servidor.

Mas eu recomendo isso:

mysql -h "hostaddress" -u "username" -p "database-name" < "sqlfile.sql"

Observe que a senha não está lá. Em seguida, solicitaria sua senha. ENTÃO, digite-a. Para que sua senha não seja registrada no histórico da linha de comando dos servidores.

Esta é uma medida de segurança básica.

Se a segurança não for uma preocupação, eu apenas removeria temporariamente a senha do usuário do banco de dados. Depois da importação - adicione-a novamente.

Dessa forma, qualquer outra conta que você compartilhe a mesma senha não será comprometida.

Parece também que no seu script de shell você não está esperando / verificando se o arquivo que você está tentando importar realmente existe. O script perl pode não estar concluído ainda.

Sterling Hamilton
fonte
1
Você perdeu a parte "automatizada" da pergunta e remover temporariamente a senha é uma péssima idéia.
PointedEars
Eu li como "restaurar" e "automatizado", o que significa "automatizado, mas não para sempre". Mas como eu disse "se a segurança não é uma preocupação". Eu concordo - é uma péssima idéia.
Sterling Hamilton
Lamento se criei confusão. O que eu quis dizer com Automated é que tenho dois scripts perl que são usados ​​para gerar o arquivo .sql, mas o comando para despejar esse arquivo no DB não é executado pelo script de shell, mas funciona absolutamente como um arquivo se eu executar esse comando em uma linha de comando. Eu quero destacar o esforço de executar esse comando na linha de comando e executá-lo através do próprio script de shell.
MUFC
1
Vaibav: se você pudesse colocar o script de shell real em sua pergunta, talvez eu possa ajudar ainda mais.
Sterling Hamilton
perl fb_apps_frm_fb.pl</l> perl fb_new_spider.pl ds_fbids.txt ds_fbids.sql` </br>mysql -h dbservername -u username -ppassword dbname < ds_fbids.sql
MUFC
3

Usar

echo "your sql script;" | mysql -u -p -h db_name
senninha
fonte
3

Para "automatizar" o processo de importação do .sqlarquivo gerado , evitando todas as armadilhas que podem estar ocultas na tentativa de passar arquivos stdine stdout, basta dizer ao MySQL para executar o .sqlarquivo gerado usando o SOURCEcomando MySQL.

A sintaxe da resposta curta, mas excelente , de Kshitij Sood , fornece o melhor ponto de partida. Em resumo, modifique o comando do OP de acordo com a sintaxe de Kshitij Sood e substitua os comandos nele pelo SOURCEcomando:

#!/bin/bash
mysql -u$user -p$password $dbname -Bse "SOURCE ds_fbids.sql
SOURCE ds_fbidx.sql"

Se o nome do banco de dados estiver incluído no .sqlarquivo gerado , ele poderá ser removido do comando

A presunção aqui é que o arquivo gerado é válido como um .sqlarquivo por si só. Por não ter o arquivo redirecionado, canalizado ou de qualquer outra maneira manipulada pelo shell, não há problema em escapar de nenhum dos caracteres na saída gerada por causa do shell. As regras com relação ao que precisa ser escapado em um .sqlarquivo, é claro, ainda se aplicam.

Como lidar com os problemas de segurança em torno da senha na linha de comando ou em um my.cnfarquivo etc. foi bem abordado em outras respostas, com algumas sugestões excelentes. Minha resposta favorita , de Danny , cobre isso, incluindo como lidar com o problema ao lidar com crontrabalhos ou qualquer outra coisa.


Para endereçar um comentário (pergunta?) Sobre a resposta curta que mencionei: Não, ele não pode ser usado com uma sintaxe HEREDOC, pois esse comando é fornecido. O HEREDOC pode ser usado na sintaxe da versão de redirecionamento (sem a -Bseopção), pois o redirecionamento de E / S é o que o HEREDOC constrói. Se você precisar da funcionalidade do HEREDOC, seria melhor usá-lo na criação de um .sqlarquivo, mesmo que seja temporário, e use esse arquivo como o "comando" para executar com a linha de lote do MySQL.

#!/bin/bash
cat >temp.sql <<SQL_STATEMENTS
...
SELECT \`column_name\` FROM \`table_name\` WHERE \`column_name\`='$shell_variable';
...
SQL_STATEMENTS
mysql -u $user -p$password $db_name -Be "SOURCE temp.sql"
rm -f temp.sql

Lembre-se de que, devido à expansão do shell, você pode usar variáveis ​​de ambiente e shell no HEREDOC. A desvantagem é que você deve escapar de cada backtick. O MySQL os usa como delimitadores para identificadores, mas o shell, que obtém a string primeiro, os usa como delimitadores de comando executável. Perca a fuga com um único backtick dos comandos do MySQL, e a coisa toda explode com erros. O problema todo pode ser resolvido usando um LimitString entre aspas para o HEREDOC:

#!/bin/bash
cat >temp.sql <<'SQL_STATEMENTS'
...
SELECT `column_name` FROM `table_name` WHERE `column_name`='constant_value';
...
SQL_STATEMENTS
mysql -u $user -p$password $db_name -Be "SOURCE temp.sql"
rm -f temp.sql

Remover a expansão do shell dessa maneira elimina a necessidade de escapar dos backticks e outros caracteres especiais do shell. Ele também remove a capacidade de usar variáveis ​​de ambiente e shell dentro dele. Isso praticamente remove os benefícios de usar um HEREDOC dentro do script de shell, para começar.

A outra opção é usar as seqüências de citação de várias linhas permitidas no Bash com a versão da sintaxe em lote (com o -Bse). Eu não conheço outras conchas, então não posso dizer se elas funcionam nela também. Você precisaria usar isso para executar mais de um .sqlarquivo com o SOURCEcomando de qualquer maneira, já que isso não é finalizado por um ;como outros comandos do MySQL, e apenas um é permitido por linha. A cadeia de linhas múltiplas pode ser simples ou dupla, com os efeitos normais na expansão do shell. Ele também possui as mesmas ressalvas que o uso da sintaxe HEREDOC para backticks, etc.

Uma solução potencialmente melhor seria usar uma linguagem de script, Perl, Python, etc., para criar o .sqlarquivo, como o OP, e SOURCEesse arquivo usando a sintaxe de comando simples na parte superior. As linguagens de script são muito melhores na manipulação de strings do que o shell, e a maioria possui procedimentos embutidos para lidar com as aspas e escapamentos necessários ao lidar com o MySQL.

Chindraba
fonte
2

Uma consideração importante para acessar o mysql a partir de um script de shell usado no cron, é que o mysql examina o usuário conectado para determinar um .my.cnf a ser carregado.

Isso não funciona com o cron. Também pode ser confuso se você estiver usando su / sudo, pois o usuário conectado pode não ser o usuário em que está executando.

Eu uso algo como:

mysql --defaults-extra-file=/path/to/specific/.my.cnf -e 'SELECT something FROM sometable'

Apenas certifique-se de que a propriedade e as permissões do usuário e do grupo estejam definidas de forma adequada e firme no arquivo .my.cnf.

Danny
fonte
1
#!/bin/sh
#Procedures = update
#Scheduled at : Every 00.05 

v_path=/etc/database_jobs
v_cnt=0

MAILTO="[email protected] [email protected] [email protected]"
touch "$v_path/db_db_log.log"

#test
mysql -uusername -ppassword -h111.111.111.111 db_name -e "CALL functionName()" > $v_path/db_db_log.log 2>&1
if [ "$?" -eq 0 ]
  then
   v_cnt=`expr $v_cnt + 1`
  mail -s "db Attendance Update has been run successfully" $MAILTO < $v_path/db_db_log.log
 else
   mail -s "Alert : db Attendance Update has been failed" $MAILTO < $v_path/db_db_log.log
   exit
fi
kartavya soni
fonte
0
mysql_config_editor set --login-path=storedPasswordKey --host=localhost --user=root --password

Como executo uma linha de comando com uma senha segura? use o editor de configuração !!!

No mysql 5.6.6, você pode armazenar a senha em um arquivo de configuração e executar comandos cli como este ....

mysql --login-path=storedPasswordKey ....

--login-path substitui variáveis ​​... host, usuário E senha. excelente né!

Artistan
fonte
0

Eu escrevi um script de shell que irá ler dados do arquivo de propriedades e, em seguida, execute o script mysql no script de shell. compartilhar isso pode ajudar outras pessoas.

#!/bin/bash
    PROPERTY_FILE=filename.properties

    function getProperty {
       PROP_KEY=$1
       PROP_VALUE=`cat $PROPERTY_FILE | grep "$PROP_KEY" | cut -d'=' -f2`
       echo $PROP_VALUE
    }

    echo "# Reading property from $PROPERTY_FILE"
    DB_USER=$(getProperty "db.username")
    DB_PASS=$(getProperty "db.password")
    ROOT_LOC=$(getProperty "root.location")
    echo $DB_USER
    echo $DB_PASS
    echo $ROOT_LOC
    echo "Writing on DB ... "
    mysql -u$DB_USER -p$DB_PASS dbname<<EOFMYSQL

    update tablename set tablename.value_ = "$ROOT_LOC" where tablename.name_="Root directory location";
    EOFMYSQL
    echo "Writing root location($ROOT_LOC) is done ... "
    counter=`mysql -u${DB_USER} -p${DB_PASS} dbname -e "select count(*) from tablename where tablename.name_='Root directory location' and tablename.value_ = '$ROOT_LOC';" | grep -v "count"`;

    if [ "$counter" = "1" ]
    then
    echo "ROOT location updated"
    fi
flopcoder
fonte