cmd批處理轉義字符%的詳細解釋


cmd批處理轉義字符%的詳細解釋

 

在命令行中使用for時不需要雙%,這源於命令解釋器對命令行與批處理的處理方式不同。

1、%是個ESCAPE字符,通常將之譯為轉義字符,但也有更形象的譯名脫逸字符、逃逸字符等。也就是說%不僅僅將與其相關的特定字符串轉義並替換為特定字符串,而且自身也會被“脫逸”。而且類似於C語言中的轉義字符"\",雙%會轉義並脫逸為單%,四%則脫為雙%。 

2、for本身是一個特殊的命令,類似於一個特化的命令解釋器,因為它的功能實現需要執行多條語句,因此它必須也具有對命令行(特指do后的命令行)分析處理的功能。而command/cmd實現for時自然會借用自身原有的命令行分析模塊,因此for具有二級轉義的特性,for中do后的語句被分兩級分析和解釋,第一級在command/cmd讀入並解釋for命令行時,第二級在for讀入並解釋do命令時,它通常會對同一命令行的進行多次解釋。 

然后,我們可以注意到,在do中使用命令行參數變量和環境變量時,不需要雙%,那是因為,這些變量在經過第一級轉義后,被替換成特定的不變的字符串常量,參與for循環的所有執行過程;而替代變量則要求在執行(do后的子命令行中)過程中不斷的動態變化,而這個變化自然仍需要通過脫逸字符來實現,因此使用雙%就是成了必然的選擇。 

另外,還需要注意到,在命令行中使用for時不需要雙%,這源於命令解釋器對命令行與批處理的處理方式不同。在早期的DOS版本中,%在命令行中不被視為轉義字符,所以不會被轉義和脫逸,所以當時無法在命令行直接引用環境變量。而使用for時,只需要一個%供for進行轉義和脫逸就夠了。在以后的命令解釋器版本中,加入了命令行轉義的支持(主要是環境變量的支持),但命令行for使用單%的傳統仍然保留了下來。 

而 cmd中的變量延遲替換是屬於特殊的情況,但不違背以上的轉義原則,只是for中的環境變量不再是常量了。

 

案例:

我在自己的一個bat文件,內容:

@echo off

if "%1" == "" (goto input_data) ELSE (goto input_var)

:input_data

set /p var=INPUT DATE(fmt:yyyyMMddHHmm):

goto start

:input_var

set /a var=%1

goto start

:start

cd  %cd%

md ..\..\to-save\TKcard\%var%

mysql -P3302 -uroot -pdst72j$mq)c%%8 -h61.160.245.119 -N -s -e"SET SESSION group_concat_max_len = 99999999;SELECT CONCAT('mysqldump -h61.160.245.119 -P3302 -uroot

-pdst72j$mq)c%%%%8 --opt -n TKCard_cn_cn_db210060000 ',GROUP_CONCAT(t.TABLE_NAME SEPARATOR  ' '),' >') FROM information_schema.TABLES t WHERE t.TABLE_SCHEMA =

'TKCard_cn_cn_db210060000' AND (t.TABLE_NAME LIKE 'dict_%%')  AND t.TABLE_NAME NOT IN('dict_keyvalue','dict_server','dict_operator_config');" > tkcard_dict.bat

for /f "delims=] tokens=1" %%a in (tkcard_dict.bat) do echo %%a ..\..\to-save\TKcard\%var%\tkcard_dict.sql >tkcard_dict.bat

call tkcard_dict.bat

上邊功能是將遠程指定數據庫中的所有基礎數據導出來。文件中寫了一個mysql 連接數據庫的腳本,並且在這個腳本里 通過“-e” 參數執行 導出所有基礎表數據的腳本代碼(即mysqldump 命令),結果沒有達到自己的預期效果,分析原因,操作內網數據庫就可以,把ip地址改為遠程數據庫地址就不行了,分析來分析去最后原來是這個 數據庫連接密碼問題,即密碼內網密碼沒有 特殊字符 % ,而遠程的這個有%,結果就是這個% 沒有特殊轉義出的問題,上邊的腳步里涉及2處相同的密碼,一處是 連接數據庫時要密碼,還一個是 對數據庫中導出所有基礎數據時用的 mysqldump命令時也要再要一次相同的密碼,這個bat文件一共2處密碼,而且都是一樣的,密碼里又涉及%,結果我就是沒有對這2處% 進行特殊轉義出問題了。上邊的是已經正確轉義了,原來密碼為:  dst72j$mq)c%8   ,  第一處正確轉義是在%前再加一個%,第二處是需要%前加3個%。 由於文章開頭%轉義規則,2個%轉義一次為%,4個%轉義后為2個%,那這里第一處要想正確連接數據庫就保證密碼為原始密碼即有自身的一個%,那就必須加一個%,那這樣第一處密碼里就有2個%,當windows 的命令行 解釋器執行連接數據庫時會轉義這2個% 為一個%,剛好和原始密碼一樣,而上邊第二處密碼要想也保證和原始密碼一樣那也要多加%,至於加幾個,我們先來看看上邊第二處涉及的邏輯先理一下。上邊一個是連接數據庫,並且后綴mysql 的參數命令-e 即 執行后邊的sql腳本,即先連接數據庫然后執行后邊腳本,結構為 mysql  -P[大寫p為端口]  -u[連接數據庫的賬號]  -p[小寫p為連接數據庫的密碼]  -h[數據庫ip地址]  -N[不顯示列信息]   -s[一行一行輸出,中間有tab分隔]   -e[執行mysql的sql語句,后跟雙引號,雙引號里為sql腳本代碼]"[雙引號里為前邊-e后跟的sql腳本-此省略下邊解釋]"    >tkcard_dict.bat[上邊sql執行的結果定向到tkcard_dict.bat文件中,由於tkcard_dict.bat前沒有路徑,那就是當前目錄,如果沒有tkcard_dict.bat文件就創建,有就覆蓋]    for...[for循環開始執行tkcard_dict.bat文件]。

這里特別把上邊-e后的雙引號中的腳本拿出來解釋: SET SESSION group_concat_max_len = 99999999;SELECT CONCAT('mysqldump -h61.160.245.119 -P3302 -uroot

-pdst72j$mq)c%%%%8 --opt -n TKCard_cn_cn_db210060000 ',GROUP_CONCAT(t.TABLE_NAME SEPARATOR  ' '),' >') FROM information_schema.TABLES t WHERE t.TABLE_SCHEMA =

'TKCard_cn_cn_db210060000' AND (t.TABLE_NAME LIKE 'dict_%%')  AND t.TABLE_NAME NOT IN('dict_keyvalue','dict_server','dict_operator_config');"

意思是先設置grop_concat函數本次查詢session的長度,然后 select  concatmysqldump代碼-是把代碼拼成字符串常量此不會執行  ,   group_concat(把從information_schema.TABLES 表中按照where條件全查出來的dict基礎表名字查出來用一個空格間隔並且拼成一個字符串)-整個group_concat 的結果作為前邊concat函數的一個參數     ,   ' >'  )    

可以看出-e后雙引號中的腳步 中那個 select 腳步功能主要就是 從 information_schema.TABLES(這個數據庫中的TABLES表中存放是這台mysql服務器中除了information_schema外的所有其他數據庫名字,以及所有數據庫中所有表名字,具體點即TABLES表中TABLE_SCHEMA字段存放是數據庫名字,TABLES表中TABLE_NAME字段存放是每個數據庫中表的名字) 表中按照where條件中給定的數據庫名字和數據表名字2個條件查詢出基礎數據表的表名字,然后把查出的基礎數據表名字通過GROUP_CONCAT 函數用一個空格間隔並且拼成一個字符串,然后再和 mysqldump命令的字符串 以及 一個'[有一個空格] >'  共三個參數 通過concat 函數 拼成一個最終的字符串 ,然互通過“ > tkcard_dict.bat ” 重定向到 tkcard_dict.bat文件中,即 tkcard_dict.bat文件中內容最終 是 :      mysqldump  -h61.160.245.119 -P3302 -uroot

-pdst72j$mq)c%%%%8 --opt -n TKCard_cn_cn_db210060000   基礎表1  基礎表2   基礎表3  ...  > 

至於for 后邊的代碼就是不太清楚了,估計就是執行上邊 新生成的 tkcard_dict.bat 文件中的內容吧,而其內容剛好就是 一個mysqldump腳本,所以就把這個mysqldump腳本執行后的結果都導入到  自定路徑下的tkcard_dict.sql 文件中把。至於最后的最上邊bat代碼中的最后的那個 “>tkcard_dict.bat” 就不知道干什么用的了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM