Làm thế nào để thực thi một lệnh MySQL từ một kịch bản shell?


131

Làm cách nào tôi có thể thực thi lệnh SQL thông qua tập lệnh shell để tôi có thể tự động thực hiện?

Tôi muốn khôi phục dữ liệu tôi đã thu thập trong tệp SQL bằng cách sử dụng tập lệnh shell. Tôi muốn kết nối với một máy chủ và khôi phục dữ liệu. Lệnh hoạt động khi được thực hiện riêng thông qua dòng lệnh SSH.

Đây là lệnh tôi sử dụng:

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

Đây là mã script shell tạo tệp ds_fbids.sqlvà chuyển nó và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

cách chính xác để làm điều này là gì?

Câu trả lời:


176

Bạn cần sử dụng -pcờ để gửi mật khẩu. Và thật khó khăn vì bạn phải có khoảng trống giữa -pvà mật khẩu.

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

Nếu bạn sử dụng một khoảng trắng sau khi -pnó làm cho máy khách mysql nhắc bạn tương tác lấy mật khẩu, và sau đó nó diễn giải đối số lệnh tiếp theo dưới dạng tên cơ sở dữ liệu:

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

Trên thực tế, tôi thích lưu trữ người dùng và mật khẩu trong ~ / .my.cnf vì vậy tôi hoàn toàn không phải đặt nó trên dòng lệnh:

[client]
user = root
password = XXXXXXXX

Sau đó:

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

Nhận xét của bạn:

Tôi chạy các lệnh mysql chế độ hàng loạt như trên trên dòng lệnh và trong các kịch bản shell mọi lúc. Thật khó để chẩn đoán những gì sai với tập lệnh shell của bạn, bởi vì bạn đã không chia sẻ tập lệnh chính xác hoặc bất kỳ đầu ra lỗi nào. Tôi đề nghị bạn chỉnh sửa câu hỏi ban đầu của bạn ở trên và cung cấp các ví dụ về những gì sai.

Ngoài ra khi tôi xử lý sự cố một tập lệnh shell, tôi sử dụng -xcờ để tôi có thể thấy cách nó thực thi từng lệnh:

$ bash -x myscript.sh

Cảm ơn đã phản hồi nhanh chóng. Tôi mệt mỏi bằng cách đặt mật khẩu vào dòng lệnh. Vấn đề thực sự là tôi đang đặt lệnh này trong tệp .sh và sau đó thực thi tập lệnh shell này. Lệnh trong tệp không được thực thi trên dòng lệnh, nhưng cùng một lệnh hoạt động hoàn toàn tốt khi tôi chỉ thực hiện lệnh trên dòng lệnh.
MUFC

+ mysql -h dbservername -u user-name -ppassword dbname</br> : No such file or directoryids.sql</br> + $'\r' : command not found2:Đây là thông báo lỗi tôi nhận được
MUFC

Ok, sau đó tôi sẽ suy luận rằng thư mục làm việc hiện tại của bạn không phải là nơi chứa tệp ids.sql. Ngoài ra, bạn có thể đã nhúng các dòng mới trong kịch bản của bạn.
Bill Karwin

Tôi có các dòng mới được nhúng trong tập lệnh shell của tôi sau mỗi lệnh. Tất cả các tập lệnh shell của tôi chứa là 3 dòng lệnh mà tôi không muốn chạy riêng vì vậy tôi đã tạo một tập lệnh shell để làm cho chúng chạy mà không cần sự can thiệp của tôi và tôi đặt dòng mới afetr mỗi comm comm. Điều đó có gây ra vấn đề không?
MUFC

tốt nhất để tránh -pnếu mật khẩu là null hoặc chuỗi rỗng, có lẽ bạn có thể cập nhật bài viết của mình? :)
James Oravec

118

Sử dụng cú pháp này:

mysql -u $user -p$passsword -Bse "command1;command2;....;commandn"

8
Tôi đã đến trang này từ google và đây là giải pháp tôi mong đợi (phù hợp với tiêu đề của câu hỏi).
Janaka R Rajapaksha

15
Một số chi tiết khác về các tùy chọn từ hướng dẫn sử dụng: -B dành cho lô, in kết quả bằng cách sử dụng tab làm dấu tách cột, với mỗi hàng trên một dòng mới. Với tùy chọn này, mysql không sử dụng tệp lịch sử. Chế độ hàng loạt dẫn đến định dạng đầu ra không cần thiết và thoát các ký tự đặc biệt. -s là chế độ im lặng. Sản xuất ít sản lượng. -e là để thực hiện tuyên bố và thoát
wranvaud

Cảm ơn bạn đã giúp đỡ! :)
haotang

Nó có thể chạy với một di sản?
zx1986

1
@ zx1986 Có và Không, với HEREDOC. Phụ thuộc vào cách bạn có nghĩa là sử dụng nó. Sử dụng nó để thay thế "command1;command2;....;commandn"một phần của câu trả lời này sẽ không hoạt động. Sử dụng nó để thay thế việc sử dụng tệp được chuyển hướng trong cú pháp của OP có thể hoạt động. Tôi đã giải quyết vấn đề đó trong câu trả lời của mình cho câu hỏi này.
Chindraba

45

Tất cả các câu trả lời trước đó là tuyệt vời. Nếu nó là một lệnh sql đơn giản, một dòng bạn muốn chạy, bạn cũng có thể sử dụng tùy chọn -e.

mysql -h <host> -u<user> -p<password> database -e \
  "SELECT * FROM blah WHERE foo='bar';"

Truy vấn trong dấu ngoặc kép ("") là những gì tôi cần làm. Cảm ơn
user3132107

Tôi hiểu rồi, và tôi lấy nó, bạn có cần đưa dấu chấm phẩy vào cuối truy vấn không?
Lori

19

Cách thực thi tập lệnh SQL, sử dụng cú pháp này:

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

Nếu bạn sử dụng máy chủ như localhost, bạn không cần phải đề cập đến nó. Bạn có thể sử dụng điều này:

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

Điều này sẽ làm việc cho Windows và Linux.

Nếu nội dung mật khẩu chứa một !dấu chấm than (dấu chấm than), bạn nên thêm một \dấu gạch chéo ngược phía trước nó.


1
Làm thế nào để xác định cơ sở dữ liệu? nó có nên ở bên trong -e, như -e "sử dụng abc; nguồn dbscript.sql" không?
Abdul Muneer

9

Cốt lõi của câu hỏi đã được trả lời nhiều lần rồi, tôi chỉ nghĩ rằng tôi đã thêm rằng backticks (`s) có beaning trong cả shell script và SQL. Nếu bạn cần sử dụng chúng trong SQL để chỉ định tên bảng hoặc cơ sở dữ liệu, bạn sẽ cần thoát chúng trong tập lệnh shell như vậy:

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

Tất nhiên, việc tạo SQL thông qua đầu vào của người dùng được nối (các đối số được truyền) không nên được thực hiện trừ khi bạn tin tưởng vào đầu vào của người dùng. Sẽ an toàn hơn rất nhiều khi đặt nó vào một ngôn ngữ kịch bản khác có hỗ trợ cho các tham số / thoát chuỗi chính xác để chèn vào MySQL.


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

(sử dụng đường dẫn đầy đủ sql_script_filenếu cần)

Nếu bạn muốn chuyển hướng ra đặt vào một tập tin

mysql -h "hostname" -u usr_name -pPASSWD "db_name" < sql_script_file > out_file

@Gus, Trước hết cảm ơn vì những bình luận có giá trị. Nó làm việc như một cơ duyên đối với tôi. Tôi muốn đầu ra là một tệp excel hoặc .csv. Làm thế nào tôi có thể đạt được điều đó. Cảm ơn trước.
Ash_and_Perl

@Ash_and_Perl Tôi chỉ chỉnh sửa câu trả lời này, cảm ơn không phải tôi, đó là câu trả lời của anh ấy. Nếu bạn có một câu hỏi của riêng bạn và bạn đã cố gắng tự tìm một giải pháp , tôi khuyên bạn nên tạo một câu hỏi. Bằng cách đó bạn có thể chi tiết những gì bạn đã cố gắng, làm thế nào nó thất bại và mọi người có thể cung cấp cho bạn một câu trả lời đầy đủ, đầy đủ (và nhận được điểm cho nó!).
Gus

5

Bạn đã quên -phoặc --password=(cái sau dễ đọc hơn):

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

(Các trích dẫn là không cần thiết nếu bạn chắc chắn rằng thông tin đăng nhập / tên của bạn không chứa dấu cách hoặc ký tự đặc biệt.)

Lưu ý rằng trang cũng vậy, nói rằng việc cung cấp thông tin đăng nhập trên dòng lệnh là không an toàn. Vì vậy, hãy làm theo lời khuyên của Bill về my.cnf.


4

Như đã nêu trước khi bạn có thể sử dụng -p để truyền mật khẩu đến máy chủ.

Nhưng tôi khuyên bạn nên điều này:

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

Thông báo mật khẩu không có ở đó. Sau đó nó sẽ nhắc mật khẩu của bạn. Tôi sẽ gõ nó vào. Vì vậy, mật khẩu của bạn không được đăng nhập vào lịch sử dòng lệnh của máy chủ.

Đây là một biện pháp bảo mật cơ bản.

Nếu bảo mật không phải là vấn đề đáng lo ngại, tôi sẽ tạm thời xóa mật khẩu khỏi người dùng cơ sở dữ liệu. Sau đó, sau khi nhập - thêm lại nó.

Bằng cách này, bất kỳ tài khoản nào khác mà bạn có thể có cùng mật khẩu sẽ không bị xâm phạm.

Dường như trong tập lệnh shell của bạn, bạn không chờ đợi / kiểm tra xem liệu tập tin bạn đang cố gắng nhập có thực sự tồn tại hay không. Kịch bản perl có thể chưa được hoàn thành.


1
Bạn đã bỏ lỡ phần "tự động" của câu hỏi và tạm thời xóa mật khẩu là một ý tưởng thực sự tồi tệ.
PointedEars

Tôi đọc nó là "khôi phục" và "tự động" có nghĩa là "tự động nhưng không phải là mãi mãi". Nhưng như tôi đã nói "nếu bảo mật không phải là vấn đề đáng lo ngại". Tôi đồng ý - đó là một ý tưởng tồi.
Sterling Hamilton

Tôi xin lỗi nếu tôi đã tạo ra sự nhầm lẫn. Điều tôi muốn nói với Automated là, tôi có hai tập lệnh perl được sử dụng để tạo tệp .sql, nhưng lệnh đổ tệp đó vào DB không được chạy bởi tập lệnh shell, nhưng nó hoạt động hoàn toàn với tập tin nếu tôi chạy lệnh đó trên một dòng lệnh. Tôi muốn làm nổi bật nỗ lực chạy lệnh đó trên dòng lệnh và chạy nó thông qua tập lệnh shell.
MUFC

1
Vaibav: nếu bạn có thể đặt tập lệnh shell thực tế bên trong câu hỏi của mình, tôi có thể giúp thêm.
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

Sử dụng

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

3

Để "tự động hóa" quá trình nhập .sqltệp được tạo , đồng thời tránh tất cả các bẫy có thể bị ẩn khi cố chuyển tệp qua stdinstdout, chỉ cần báo cho MySQL thực hiện .sqltệp được tạo bằng cách sử dụngSOURCE lệnh trong MySQL.

Cú pháp trong câu trả lời ngắn, nhưng xuất sắc , từ Kshitij Sood , đưa ra điểm khởi đầu tốt nhất. Nói tóm lại, sửa đổi lệnh của OP theo cú pháp của Kshitij Sood và thay thế các lệnh trong đó bằng SOURCElệnh:

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

Nếu tên cơ sở dữ liệu được bao gồm trong tạo .sql tệp , nó có thể được loại bỏ khỏi lệnh.

Giả định ở đây là tệp được tạo có giá trị như một .sqltệp của chính nó. Bằng cách không có tệp được chuyển hướng, đường ống hoặc theo bất kỳ cách nào khác được xử lý bởi trình bao, không có vấn đề gì về việc cần phải thoát bất kỳ ký tự nào trong đầu ra được tạo vì trình bao. Các quy tắc liên quan đến những gì cần phải thoát trong một .sqltập tin, tất nhiên, vẫn được áp dụng.

Làm thế nào để giải quyết các vấn đề bảo mật xung quanh mật khẩu trên dòng lệnh, hoặc trong một my.cnftệp, v.v., đã được giải quyết tốt trong các câu trả lời khác, với một số gợi ý tuyệt vời. Câu trả lời yêu thích của tôi , từ Daniel , bao gồm điều đó, bao gồm cả cách xử lý vấn đề khi giải quyết croncông việc, hoặc bất cứ điều gì khác.


Để giải quyết một nhận xét (câu hỏi?) Về câu trả lời ngắn gọn mà tôi đã đề cập: Không, nó không thể được sử dụng với cú pháp HEREDOC, vì lệnh shell đó được đưa ra. HEREDOC có thể được sử dụng trong cú pháp phiên bản chuyển hướng , (không có -Bsetùy chọn), vì chuyển hướng I / O là những gì HEREDOC được xây dựng xung quanh. Nếu bạn cần chức năng của HEREDOC, sẽ tốt hơn nếu sử dụng nó trong việc tạo .sqltệp, ngay cả khi đó là tạm thời và sử dụng tệp đó làm "lệnh" để thực thi với dòng lô 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

Hãy nhớ rằng vì mở rộng shell, bạn có thể sử dụng các biến shell và môi trường trong HEREDOC. Mặt trái là bạn phải thoát khỏi mọi backtick. MySQL sử dụng chúng làm các dấu phân cách cho các định danh nhưng shell, lấy chuỗi đầu tiên, sử dụng chúng làm các dấu phân cách lệnh thực thi. Bỏ lỡ lối thoát trên một backtick duy nhất của các lệnh MySQL và toàn bộ sự việc phát nổ với lỗi. Toàn bộ vấn đề có thể được giải quyết bằng cách sử dụng Giới hạn được trích dẫn cho 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

Loại bỏ mở rộng shell theo cách đó giúp loại bỏ sự cần thiết phải thoát khỏi backticks và các ký tự đặc biệt khác của shell. Nó cũng loại bỏ khả năng sử dụng các biến shell và môi trường bên trong nó. Điều đó khá nhiều loại bỏ các lợi ích của việc sử dụng HEREDOC trong tập lệnh shell để bắt đầu.

Tùy chọn khác là sử dụng các chuỗi trích dẫn nhiều dòng được phép trong Bash với phiên bản cú pháp bó (với -Bse). Tôi không biết các loại vỏ khác, vì vậy tôi không thể nói nếu chúng cũng hoạt động trong đó. Bạn sẽ cần phải sử dụng điều này để thực thi nhiều hơn một .sqltệp bằng SOURCElệnh, vì điều đó không bị chấm dứt bởi một ;lệnh MySQL khác và chỉ một tệp được phép trên mỗi dòng. Chuỗi nhiều dòng có thể được trích dẫn một hoặc hai lần, với các hiệu ứng bình thường đối với việc mở rộng hệ vỏ. Nó cũng có những cảnh báo tương tự như sử dụng cú pháp HEREDOC dành cho backticks, v.v.

Một giải pháp tiềm năng tốt hơn là sử dụng ngôn ngữ kịch bản, Perl, Python, v.v., để tạo .sqltệp, như OP đã làm và SOURCEtệp đó sử dụng cú pháp lệnh đơn giản ở trên cùng. Các ngôn ngữ kịch bản lệnh xử lý chuỗi tốt hơn nhiều so với trình bao, và hầu hết đều có các quy trình được xây dựng để xử lý trích dẫn và thoát cần thiết khi giao dịch với MySQL.


2

Một cân nhắc quan trọng để truy cập mysql từ tập lệnh shell được sử dụng trong cron, đó là mysql nhìn vào người dùng đã đăng nhập để xác định .my.cnf để tải.

Điều đó không làm việc với cron. Nó cũng có thể gây nhầm lẫn nếu bạn đang sử dụng su / sudo vì người dùng đã đăng nhập có thể không phải là người dùng bạn đang chạy.

Tôi sử dụng một cái gì đó như:

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

Chỉ cần đảm bảo rằng quyền sở hữu và quyền của người dùng và nhóm được đặt phù hợp và chặt chẽ trên tệp .my.cnf.


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

v_path=/etc/database_jobs
v_cnt=0

MAILTO="indd@abc.in joanson@abc.in sturt@abc.in"
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

0
mysql_config_editor set --login-path=storedPasswordKey --host=localhost --user=root --password

Làm cách nào để thực thi một dòng lệnh với mật khẩu an toàn ?? sử dụng trình chỉnh sửa cấu hình !!!

Kể từ mysql 5.6.6, bạn có thể lưu mật khẩu trong tệp cấu hình và sau đó thực thi các lệnh cli như thế này ....

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

--login-path thay thế các biến ... máy chủ, người dùng VÀ mật khẩu. xuất sắc đúng không!



0

Tôi đã viết một tập lệnh shell sẽ đọc dữ liệu từ tệp thuộc tính và sau đó chạy tập lệnh mysql trên tập lệnh shell. chia sẻ điều này có thể giúp đỡ người khác.

#!/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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.