Bagaimana cara menjalankan perintah MySQL dari skrip shell?

131

Bagaimana saya bisa menjalankan perintah SQL melalui skrip shell sehingga saya bisa membuatnya otomatis?

Saya ingin mengembalikan data yang saya kumpulkan dalam file SQL menggunakan skrip shell. Saya ingin terhubung ke server dan mengembalikan data. Perintah ini berfungsi ketika dijalankan secara terpisah melalui baris perintah SSH.

Ini adalah perintah yang saya gunakan:

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

Ini adalah kode skrip shell yang membuat file ds_fbids.sqldan mengirimkannya ke 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

Apa cara yang benar untuk melakukan ini?

MUFC
sumber

Jawaban:

176

Anda perlu menggunakan -pbendera untuk mengirim kata sandi. Dan itu rumit karena Anda tidak boleh memiliki ruang antara -pdan kata sandi.

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

Jika Anda menggunakan spasi setelah -pitu membuat klien mysql meminta Anda secara interaktif untuk kata sandi, dan kemudian menafsirkan argumen perintah berikutnya sebagai nama database:

$ 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'

Sebenarnya, saya lebih suka menyimpan pengguna dan kata sandi di ~ / .my.cnf jadi saya tidak harus meletakkannya di command-line sama sekali:

[client]
user = root
password = XXXXXXXX

Kemudian:

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

Berikan komentar Anda:

Saya menjalankan batch-mode mysql perintah seperti di atas pada baris perintah dan skrip shell sepanjang waktu. Sulit untuk mendiagnosis apa yang salah dengan skrip shell Anda, karena Anda belum membagikan skrip yang tepat atau output kesalahan apa pun. Saya sarankan Anda mengedit pertanyaan awal Anda di atas dan memberikan contoh kesalahan.

Juga ketika saya memecahkan masalah skrip shell saya menggunakan -xflag sehingga saya bisa melihat bagaimana itu mengeksekusi setiap perintah:

$ bash -x myscript.sh
Bill Karwin
sumber
Terima kasih atas tanggapan yang cepat. Saya lelah dengan memasukkan kata sandi di baris perintah itu sendiri. Masalah sebenarnya adalah saya meletakkan perintah ini dalam file .sh dan kemudian mengeksekusi skrip shell ini. Perintah dalam file tidak dieksekusi pada baris perintah, tetapi perintah yang sama berfungsi dengan baik ketika saya mengeksekusi hanya perintah pada baris perintah.
MUFC
+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:Ini adalah pesan kesalahan yang saya dapatkan
MUFC
Ok, maka saya akan menyimpulkan bahwa direktori kerja Anda saat ini tidak di mana file ids.sql berada. Anda juga mungkin telah menyematkan baris baru dalam skrip Anda.
Bill Karwin 8/11
Saya memiliki baris baru yang tertanam di skrip shell saya setelah setiap perintah. Semua yang terdapat pada skrip shell saya adalah 3 perintah baris perintah yang saya tidak ingin jalankan secara terpisah, jadi saya membuat skrip shell untuk menjalankannya tanpa campur tangan saya dan saya meletakkan baris baru di atas setiap perintah. Apakah itu yang menyebabkan masalah?
MUFC
terbaik untuk menghindari -pjika kata sandi adalah null atau string kosong, mungkin Anda dapat memperbarui posting Anda? :)
James Oravec
118

Gunakan sintaks ini:

mysql -u $user -p$passsword -Bse "command1;command2;....;commandn"
Kshitij Sood
sumber
8
Saya masuk ke halaman ini dari google dan ini adalah solusi yang saya harapkan (sesuai dengan judul pertanyaan).
Janaka R Rajapaksha
15
Beberapa rincian lebih lanjut tentang opsi dari manual: -B adalah untuk batch, hasil cetak menggunakan tab sebagai pemisah kolom, dengan setiap baris pada baris baru. Dengan opsi ini, mysql tidak menggunakan file riwayat. Mode batch menghasilkan format output nontabular dan keluar dari karakter khusus. -s adalah mode diam. Menghasilkan lebih sedikit output. -e adalah untuk menjalankan pernyataan dan berhenti
wranvaud
Terima kasih atas bantuan Anda! :)
haotang
Bisakah itu berjalan dengan heredoc?
zx1986
1
@ zx1986 Ya dan Tidak, ke HEREDOC. Tergantung pada bagaimana Anda menggunakannya. Menggunakannya untuk mengganti "command1;command2;....;commandn"bagian dari jawaban ini tidak akan berhasil. Menggunakannya untuk menggantikan penggunaan file yang diarahkan pada sintaks OP dapat bekerja. Saya telah membahas masalah itu dalam jawaban saya untuk pertanyaan ini.
Chindraba
45

Semua jawaban sebelumnya sangat bagus. Jika sederhana, perintah satu baris sql yang ingin Anda jalankan, Anda juga bisa menggunakan opsi -e.

mysql -h <host> -u<user> -p<password> database -e \
  "SELECT * FROM blah WHERE foo='bar';"
Jericon
sumber
Permintaan dalam tanda kutip ganda ("") adalah apa yang perlu saya lakukan. Terima kasih
user3132107
Saya mengerti, dan saya pikir Anda perlu menyertakan tanda titik koma di akhir kueri?
Lori
19

Cara menjalankan skrip SQL, gunakan sintaks ini:

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

Jika Anda menggunakan host sebagai localhost, Anda tidak perlu menyebutkannya. Anda bisa menggunakan ini:

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

Ini seharusnya berfungsi untuk Windows dan Linux.

Jika konten kata sandi berisi !(tanda seru) Anda harus menambahkan \(garis miring terbalik) di depannya.

Bandara Milinda
sumber
1
Bagaimana cara menentukan basis data? haruskah itu di dalam -e, seperti -e "gunakan abc; source dbscript.sql"?
Abdul Muneer
9

Inti dari pertanyaan telah dijawab beberapa kali, saya hanya berpikir saya akan menambahkan bahwa backticks (`s) telah mengupas baik skrip shell dan SQL. Jika Anda perlu menggunakannya dalam SQL untuk menentukan tabel atau nama database, Anda harus menghindarinya dalam skrip shell seperti:

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;"

Tentu saja, menghasilkan SQL melalui input pengguna gabungan (argumen yang disahkan) tidak boleh dilakukan kecuali Anda memercayai input pengguna. Akan jauh lebih aman untuk meletakkannya dalam bahasa skrip lain dengan dukungan untuk parameter / dengan benar lolos dari string untuk dimasukkan ke dalam MySQL.

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

(gunakan jalur lengkap untuk sql_script_filejika diperlukan)

Jika Anda ingin mengarahkan keluar put ke file

mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file > out_file
merambat
sumber
@ Tuhan, Pertama-tama terima kasih atas komentar yang berharga. Itu bekerja seperti pesona bagi saya. Saya ingin output menjadi file excel atau .csv. bagaimana saya bisa mencapainya. Terima kasih sebelumnya.
Ash_and_Perl
@Ash_and_Perl Saya hanya mengedit jawaban ini, terima kasih bukan aku, ini jawabannya. Jika Anda memiliki pertanyaan sendiri, dan Anda sudah mencoba menemukan solusi sendiri , saya sarankan Anda membuat pertanyaan. Dengan begitu Anda dapat merinci apa yang Anda coba, bagaimana gagal, dan orang-orang dapat memberi Anda jawaban yang lengkap dan lengkap (dan dapatkan poin untuk itu!).
Gus
5

Anda lupa -patau --password=(yang terakhir lebih baik dibaca):

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

(Kutipan tidak perlu jika Anda yakin bahwa kredensial / nama Anda tidak mengandung spasi atau karakter khusus shell.)

Perhatikan bahwa halaman manual juga mengatakan bahwa memberikan kredensial pada baris perintah tidak aman. Jadi, ikuti saran Bill tentang my.cnf.

PointedEars
sumber
4

Seperti yang dinyatakan sebelumnya, Anda dapat menggunakan -p untuk meneruskan kata sandi ke server.

Tetapi saya merekomendasikan ini:

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

Perhatikan kata sandinya tidak ada. Maka akan meminta kata sandi Anda. KEMUDIAN saya akan mengetiknya. Agar kata sandi Anda tidak masuk ke riwayat baris perintah server.

Ini adalah langkah pengamanan dasar.

Jika keamanan tidak menjadi masalah, saya hanya akan menghapus sementara kata sandi dari pengguna basis data. Kemudian setelah impor - tambahkan kembali.

Dengan cara ini, akun lain yang mungkin Anda miliki yang memiliki kata sandi yang sama tidak akan dikompromikan.

Tampaknya juga dalam skrip shell Anda, Anda tidak menunggu / memeriksa untuk melihat apakah file yang Anda coba impor benar-benar ada. Script perl mungkin belum selesai.

Sterling Hamilton
sumber
1
Anda melewatkan bagian "otomatis" dari pertanyaan, dan menghapus kata sandi untuk sementara adalah ide yang sangat buruk.
PointedEars
Saya membacanya sebagai "mengembalikan" dan "otomatis" yang berarti "otomatis tetapi tidak selamanya". Tapi seperti saya katakan "jika keamanan bukan masalah". Saya setuju - itu ide yang BENAR-BENAR buruk.
Sterling Hamilton
Saya minta maaf jika saya telah membuat kebingungan. Apa yang saya maksud dengan Automated adalah, saya memiliki dua skrip perl yang digunakan untuk menghasilkan file .sql, tetapi perintah untuk membuang file tersebut ke DB tidak dijalankan oleh skrip shell, tetapi ia benar-benar berfungsi jika saya menjalankan perintah itu pada baris perintah. Saya ingin menghilangkan upaya menjalankan perintah itu pada baris perintah dan menjalankannya melalui skrip shell itu sendiri.
MUFC
1
Vaibav: jika Anda bisa memasukkan skrip shell yang sebenarnya di dalam pertanyaan Anda, saya mungkin bisa membantu lebih lanjut.
Sterling Hamilton
perl fb_apps_frm_fb.pl</br> perl fb_new_spider.pl ds_fbids.txt ds_fbids.sql` </br>mysql -h dbservername -u username -ppassword dbname < ds_fbids.sql
MUFC
3

Menggunakan

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

Untuk "mengotomatisasi" proses mengimpor .sqlfile yang dihasilkan , sambil menghindari semua jebakan yang dapat disembunyikan dalam mencoba untuk melewati file stdindan stdout, katakan saja pada MySQL untuk mengeksekusi .sqlfile yang dihasilkan menggunakan SOURCEperintah di MySQL.

Sintaks dalam jangka pendek, tetapi sangat baik, jawaban , dari Kshitij Sood , memberikan yang terbaik titik awal. Singkatnya, modifikasi perintah OP sesuai dengan sintaks Kshitij Sood dan ganti perintah di dalamnya dengan SOURCEperintah:

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

Jika nama database termasuk dalam .sqlfile yang dihasilkan , itu bisa dihapus dari perintah.

Anggapan di sini adalah bahwa file yang dihasilkan valid sebagai .sqlfile sendiri. Dengan tidak memiliki file yang dialihkan, disalurkan, atau dengan cara lain ditangani oleh shell, tidak ada masalah dengan kebutuhan untuk melarikan diri dari salah satu karakter dalam output yang dihasilkan karena shell. Aturan berkenaan dengan apa yang perlu diloloskan dalam .sqlfile, tentu saja, masih berlaku.

Bagaimana menangani masalah keamanan di sekitar kata sandi pada baris perintah, atau dalam my.cnffile, dll., Telah ditangani dengan baik dalam jawaban lain, dengan beberapa saran yang sangat baik. Jawaban favorit saya , dari Danny , mencakup hal itu, termasuk bagaimana menangani masalah ketika berhadapan dengan cronpekerjaan, atau apa pun.


Untuk menjawab komentar (pertanyaan?) Pada jawaban singkat yang saya sebutkan: Tidak, itu tidak dapat digunakan dengan sintaks HEREDOC, karena perintah shell diberikan. HEREDOC dapat digunakan dalam sintaks versi redirection , (tanpa -Bseopsi), karena I / O redirection adalah apa yang dibangun oleh HEREDOC. Jika Anda memerlukan fungsionalitas HEREDOC, akan lebih baik untuk menggunakannya dalam pembuatan .sqlfile, meskipun itu hanya sementara, dan gunakan file itu sebagai "perintah" untuk mengeksekusi dengan baris batch 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

Ingatlah bahwa karena ekspansi shell Anda dapat menggunakan variabel shell dan lingkungan di dalam HEREDOC. Sisi buruknya adalah Anda harus melarikan diri dari setiap backtick. MySQL menggunakannya sebagai pembatas untuk pengidentifikasi tetapi shell, yang mendapatkan string pertama, menggunakannya sebagai pembatas perintah yang dapat dieksekusi. Kehilangan jalan keluar dengan satu backtick dari perintah MySQL, dan semuanya meledak dengan kesalahan. Seluruh masalah dapat diselesaikan dengan menggunakan LimitString yang dikutip untuk 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

Menghapus ekspansi shell dengan cara itu menghilangkan kebutuhan untuk keluar dari backticks, dan karakter khusus shell lainnya. Ini juga menghilangkan kemampuan untuk menggunakan variabel shell dan lingkungan di dalamnya. Itu cukup banyak menghilangkan manfaat menggunakan HEREDOC di dalam skrip shell untuk memulai.

Opsi lainnya adalah menggunakan string yang dikutip multi-baris yang diizinkan dalam Bash dengan versi sintaks batch (dengan -Bse). Saya tidak tahu cangkang lain, jadi saya tidak bisa mengatakan jika mereka bekerja di sana juga. Anda perlu menggunakan ini untuk mengeksekusi lebih dari satu .sqlfile dengan SOURCEperintah, karena itu tidak dihentikan oleh ;seperti perintah MySQL lainnya, dan hanya satu yang diperbolehkan per baris. String multi-line dapat berupa tanda kutip tunggal atau ganda, dengan efek normal pada ekspansi shell. Ini juga memiliki peringatan yang sama seperti menggunakan sintaks HEREDOC untuk backticks, dll.

Solusi yang berpotensi lebih baik adalah dengan menggunakan bahasa scripting, Perl, Python, dll., Untuk membuat .sqlfile, seperti yang dilakukan OP, dan SOURCEfile itu menggunakan sintaks perintah sederhana di atas. Bahasa scripting jauh lebih baik dalam manipulasi string daripada shell, dan sebagian besar memiliki prosedur bawaan untuk menangani penawaran dan pelarian yang diperlukan ketika berhadapan dengan MySQL.

Chindraba
sumber
2

Pertimbangan penting untuk mengakses mysql dari skrip shell yang digunakan dalam cron, adalah bahwa mysql melihat pengguna yang login untuk menentukan .my.cnf yang akan dimuat.

Itu tidak bekerja dengan cron. Itu juga bisa membingungkan jika Anda menggunakan su / sudo karena pengguna yang masuk mungkin bukan pengguna yang Anda jalankan.

Saya menggunakan sesuatu seperti:

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

Pastikan bahwa kepemilikan dan izin pengguna dan grup diatur dengan benar dan erat pada file .my.cnf.

Danny
sumber
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
sumber
0
mysql_config_editor set --login-path=storedPasswordKey --host=localhost --user=root --password

Bagaimana cara mengeksekusi baris perintah dengan kata sandi yang aman ?? gunakan editor konfigurasi !!!

Pada mysql 5.6.6 Anda dapat menyimpan kata sandi dalam file config dan kemudian menjalankan perintah cli seperti ini ....

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

--login-path menggantikan variabel ... host, pengguna DAN kata sandi. sangat bagus!

Artistan
sumber
0

Saya telah menulis skrip shell yang akan membaca data dari file properti dan kemudian menjalankan skrip mysql pada skrip shell. berbagi ini dapat membantu orang lain.

#!/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
sumber