批處理技術內幕 ECHO命令介紹_DOS/BAT

來源:互聯網
上載者:User
眾所周知,如果echo後面跟一個環境變數,但是該變數卻為空白時,相當於不加任何參數的echo,即輸出當前echo是on還是off。很多文章或者教程給出的解決方案都是在echo後面加一個點號echo.,這樣就會輸出空行。
複製代碼 代碼如下:

@echo off
echo %demon.tw%
:: ECHO is off.
echo.%demon.tw%

pause據我所知,用echo輸出空行至少有十種方法:
複製代碼 代碼如下:

@echo off

echo=
echo,
echo;

echo+
echo/
echo[
echo]

echo:
echo.
echo\
pause

這十種方法可以分為三組,每組的效率依次遞減。可悲的是,那些被奉為經典的教程給出的卻是效率最低那組中的echo.

echo.不僅效率低下,而且還容易引發錯誤:
複製代碼 代碼如下:

@echo off
cd .>echo
echo.
pause

我知道你很難接受,但事實的確如此。

第一組中echo後面的=,;都是批處理中的分隔字元,所以CMD可以正確地解析出echo命令,並把=,;作為echo命令的參數。是的,你沒有看錯,分隔字元並不是用來分隔命令與參數,它們通常是參數的一部分。既然是參數,那麼為什麼不會被輸出?那是因為echo命令直接跳過了參數的第一個字元,從第二個字元開始輸出,而第二個字元是NUL,所以輸出了空行。

你可能又要問,那為什麼用空格做分隔字元卻不能輸出空行呢?那是因為在輸出之前,CMD要檢查echo命令的參數是不是on或者off,或者參數為空白:首先跳過所有空白字元,如果跳過之後字串就結束了,那麼就認為沒有加參數,輸出echo是on還是off;如果字串沒有結束,就調用wcsnicmp函數來判斷剩下的字串是否為on或者off,進而修改echo的狀態。

因此加上很多空格也是一樣的效果:
複製代碼 代碼如下:

@echo off
echo
echo on
echo
pause

而對於第二和第三組,事情就沒那麼簡單了,由於echo後面跟的並不是分隔字元,所以解析之後會被當成一個整體,而echo+ echo/等等顯然又不是內部命令,CMD會把它們當做外部命令進行搜尋。嗯,你知道,搜尋是很花時間的,這就是為什麼它們的效率低於第一組。

可惜的是,CMD花了很大力氣搜尋,卻仍然找不到這樣的外部命令,這時候它會嘗試著修複(Fix)命令,看看命令中是否有某些字元(如圖):


可以看到,CMD對:.\的處理跟+[]/不太一樣,如果是+[]/,CMD會直接把它們從命令中刪除並且添加到原有參數的前面;而如果是:.\並且CMD拓展是開啟的話,那麼會多調用一次GetFileAttributes函數擷取檔案屬性,多調用一次函數自然會多花一些時間,所以第三組的效率又稍稍比第二組的低些。

再來解釋一下為什麼echo.有時候會引起錯誤。檔案名稱中是不能出現:.\的,理論上GetFileAttributes函數都應該返回-1(INVALID_FILE_ATTRIBUTES),然而事實卻不是如此,我也不知道這算不算GetFileAttributes函數的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程式,就會發現echo.那行返回的不是-1。

如果GetFileAttributes函數返回的不是-1(一般表示檔案不存在),也不是0×10(表示檔案是檔案夾),那麼命令還是會保持原來的樣子,當成外部命令運行。
複製代碼 代碼如下:

@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

關閉了CMD拓展,沒有問題。
複製代碼 代碼如下:

@echo off
md echo
echo.
pause

echo是檔案夾而不是檔案,沒有問題。

最後總結一下吧,在大部分情況下,你都應該使用第一組的echo, echo; echo=來進行輸出,它們的效率跟echo (空格)是一樣的,並且可以用來輸出on或者off,在變數為空白時還能輸出空行。

但是echo, echo; echo=卻不能輸出以/?開頭的行,如果你需要,可以使用第二組的echo+ echo/ echo[ echo],它們的效率低一些,但能保證原樣輸出。

我不建議你使用第三組的echo: echo. echo\,如果你仍然要像垃圾教程裡面那樣用,我也沒有辦法。
作者: Demon
連結: http://demon.tw/reverse/cmd-internal-echo.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.