批處理技術(shù)內(nèi)幕 ECHO命令介紹
@echo off
echo %demon.tw%
:: ECHO is off.
echo.%demon.tw%
pause據(jù)我所知,用echo輸出空行至少有十種方法:
@echo off
echo=
echo,
echo;
echo+
echo/
echo[
echo]
echo:
echo.
echo\
pause
這十種方法可以分為三組,每組的效率依次遞減??杀氖?,那些被奉為經(jīng)典的教程給出的卻是效率最低那組中的echo.
echo.不僅效率低下,而且還容易引發(fā)錯(cuò)誤:
@echo off
cd .>echo
echo.
pause
我知道你很難接受,但事實(shí)的確如此。
第一組中echo后面的=,;都是批處理中的分隔符,所以CMD可以正確地解析出echo命令,并把=,;作為echo命令的參數(shù)。是的,你沒(méi)有看錯(cuò),分隔符并不是用來(lái)分隔命令與參數(shù),它們通常是參數(shù)的一部分。既然是參數(shù),那么為什么不會(huì)被輸出?那是因?yàn)閑cho命令直接跳過(guò)了參數(shù)的第一個(gè)字符,從第二個(gè)字符開(kāi)始輸出,而第二個(gè)字符是NUL,所以輸出了空行。
你可能又要問(wèn),那為什么用空格做分隔符卻不能輸出空行呢?那是因?yàn)樵谳敵鲋?,CMD要檢查echo命令的參數(shù)是不是on或者off,或者參數(shù)為空:首先跳過(guò)所有空白字符,如果跳過(guò)之后字符串就結(jié)束了,那么就認(rèn)為沒(méi)有加參數(shù),輸出echo是on還是off;如果字符串沒(méi)有結(jié)束,就調(diào)用wcsnicmp函數(shù)來(lái)判斷剩下的字符串是否為on或者off,進(jìn)而修改echo的狀態(tài)。
因此加上很多空格也是一樣的效果:
@echo off
echo
echo on
echo
pause
而對(duì)于第二和第三組,事情就沒(méi)那么簡(jiǎn)單了,由于echo后面跟的并不是分隔符,所以解析之后會(huì)被當(dāng)成一個(gè)整體,而echo+ echo/等等顯然又不是內(nèi)部命令,CMD會(huì)把它們當(dāng)做外部命令進(jìn)行搜索。嗯,你知道,搜索是很花時(shí)間的,這就是為什么它們的效率低于第一組。
可惜的是,CMD花了很大力氣搜索,卻仍然找不到這樣的外部命令,這時(shí)候它會(huì)嘗試著修復(fù)(Fix)命令,看看命令中是否有某些字符(如圖):
可以看到,CMD對(duì):.\的處理跟+[]/不太一樣,如果是+[]/,CMD會(huì)直接把它們從命令中刪除并且添加到原有參數(shù)的前面;而如果是:.\并且CMD拓展是開(kāi)啟的話(huà),那么會(huì)多調(diào)用一次GetFileAttributes函數(shù)獲取文件屬性,多調(diào)用一次函數(shù)自然會(huì)多花一些時(shí)間,所以第三組的效率又稍稍比第二組的低些。
再來(lái)解釋一下為什么echo.有時(shí)候會(huì)引起錯(cuò)誤。文件名中是不能出現(xiàn):.\的,理論上GetFileAttributes函數(shù)都應(yīng)該返回-1(INVALID_FILE_ATTRIBUTES),然而事實(shí)卻不是如此,我也不知道這算不算GetFileAttributes函數(shù)的BUG:
#include <stdio.h>
#include <windows.h>
int main()
{
FILE *fp = fopen("echo", "wb");
fclose(fp);
printf("0x%x\n", GetFileAttributes("echo:"));
printf("0x%x\n", GetFileAttributes("echo."));
printf("0x%x\n", GetFileAttributes("echo/"));
return 0;
}
如果你測(cè)試一下上面的C程序,就會(huì)發(fā)現(xiàn)echo.那行返回的不是-1。
如果GetFileAttributes函數(shù)返回的不是-1(一般表示文件不存在),也不是0×10(表示文件是文件夾),那么命令還是會(huì)保持原來(lái)的樣子,當(dāng)成外部命令運(yùn)行。
@echo off
cd .>echo
echo.
pause
‘echo.' is not recognized as an internal or external command, operable program or batch file.
@echo off
cd .>echo
setlocal disableextensions
echo.
pause
關(guān)閉了CMD拓展,沒(méi)有問(wèn)題。
@echo off
md echo
echo.
pause
echo是文件夾而不是文件,沒(méi)有問(wèn)題。
最后總結(jié)一下吧,在大部分情況下,你都應(yīng)該使用第一組的echo, echo; echo=來(lái)進(jìn)行輸出,它們的效率跟echo (空格)是一樣的,并且可以用來(lái)輸出on或者off,在變量為空時(shí)還能輸出空行。
但是echo, echo; echo=卻不能輸出以/?開(kāi)頭的行,如果你需要,可以使用第二組的echo+ echo/ echo[ echo],它們的效率低一些,但能保證原樣輸出。
我不建議你使用第三組的echo: echo. echo\,如果你仍然要像垃圾教程里面那樣用,我也沒(méi)有辦法。
作者: Demon
鏈接: http://demon.tw/reverse/cmd-internal-echo.html
相關(guān)文章
Windows下寫(xiě)一個(gè)文件備份腳本(專(zhuān)用備份的)
大半個(gè)月的日記加密文件受損,無(wú)法恢復(fù)。于是決定寫(xiě)一個(gè)專(zhuān)用備份的腳本文件,需要的朋友可以參考下2014-02-02自動(dòng)生成批量執(zhí)行SQL腳本的批處理實(shí)例演示
DBA那邊給我導(dǎo)出了所有的存儲(chǔ)、函數(shù)等等對(duì)象的創(chuàng)建腳本,有上千個(gè)文件,接下來(lái)為大家介紹下如何將這些對(duì)象創(chuàng)建腳本導(dǎo)入到另外一個(gè)庫(kù)2013-04-04批處理萬(wàn)年歷實(shí)現(xiàn)代碼(包括農(nóng)歷日期)
這篇文章主要介紹了批處理萬(wàn)年歷實(shí)現(xiàn)代碼(包括農(nóng)歷日期),月歷查詢(xún)工具 最初發(fā)表于CN-DOS,輸出數(shù)字排序有問(wèn)題大家可以自行修復(fù)一下2020-06-06DOS批處理高級(jí)教程 第二章 DOS循環(huán)for命令詳解
批處理 bat中的for命令的作用,非常的不錯(cuò),可以節(jié)省很多效率,它可以讀取文章的沒(méi)一行,循環(huán)執(zhí)行ping命令,探索端口,學(xué)習(xí)批處理如果不學(xué)習(xí)for將是個(gè)遺憾,希望大家多看看for 命令的實(shí)際應(yīng)用的例子2016-09-09批處理備份文件夾和文件后發(fā)布文件夾至網(wǎng)站
使用批處理備份文件夾和文件后再把備份的文件夾發(fā)布出去(例如:網(wǎng)站),對(duì)批處理感興趣的朋友可以參考下啊,或許對(duì)你學(xué)習(xí)批處理有所幫助2013-02-02bat批處理徹底隱藏文件的方法(使用虛擬磁盤(pán)實(shí)現(xiàn))
這篇文章主要介紹了bat批處理徹底隱藏文件的方法,本文使用創(chuàng)建虛擬磁盤(pán)的方法實(shí)現(xiàn),虛擬磁盤(pán)的盤(pán)符定為X盤(pán),會(huì)出現(xiàn)在我的電腦中,使用時(shí)顯示,不用時(shí)隱藏2014-06-06Windows下bat批處理腳本使用telnet批量檢測(cè)遠(yuǎn)程端口小記
這篇文章主要介紹了Windows下bat批處理腳本使用telnet批量檢測(cè)遠(yuǎn)程端口小記,需要的朋友可以參考下2015-09-09DOS下測(cè)試通訊的常用命令分享(dir>prn)
DOS下測(cè)試通訊的常用命令,需要的朋友可以參考下2012-06-06