當(dāng)前位置: 首頁(yè)IT技術(shù) → 批處理(bat)利用set p與重定向輸入分行獲取文本內(nèi)容

批處理(bat)利用set p與重定向輸入分行獲取文本內(nèi)容

更多

起因是前幾天的某個(gè)帖子中看到 cmd<1.txt 的用法,原以為1.txt 中的 pause 之所以被跳過(guò)是因?yàn)閳?zhí)行完后馬上接收到了一個(gè)回車符,于是我把1.txt 中的所有 pause 都改成 pause&rem ,并去除所有回車符進(jìn)行試驗(yàn),下為去除回車符的代碼:

 

1.  

@echo off&setlocal enabledelayedexpansion

2.  

set hh=^

3.   
4.   
5.  

::獲取換行符

6.  

for %%a in (

7.  

        "@echo off" "pause&rem" "echo abc" "pause&rem"

8.  

) do set str=!str!!hh!%%~a

9.  

echo !str:~2!>3.txt

10.      

::只用換行符斷行

11.      

cmd<3.txt

12.      

echo;

13.      

echo ________end________

14.      

Pause

 

假設(shè)修改后 1.txt內(nèi)容如下(測(cè)試時(shí),此文本中不存在回車符):

 

1.  

@echo off

2.  

pause&rem

3.  

echo abc

4.  

pause&rem

 

結(jié)果仍然沒(méi)有等待用戶輸入,并且還吞掉了下一行 echo 的第一個(gè)字符,導(dǎo)致 cmd 顯示:

 

1.  

        請(qǐng)按任意鍵繼續(xù). . .

2.  

        'cho' 不是內(nèi)部或外部命令,也不是可運(yùn)行的程序

3.  

        或批處理文件。

4.  

        請(qǐng)按任意鍵繼續(xù). . .

 

對(duì)此感到非常疑惑,百思不得其解之下去請(qǐng)教寒夜版主,他問(wèn)我 pause 等待的是什么輸入,我才忽然醒悟,原來(lái) pause 等待的是“任意鍵”,也就是說(shuō),它把 echo 的 e 當(dāng)作用戶輸入給接收了(因?yàn)樾心┑?0D 0A被 cmd 接收了,所以 pause 接收的第一個(gè)字符就是下一行的首字符 e),因此這里用 pause 無(wú)法實(shí)現(xiàn)暫停的效果,這就推翻了我原來(lái)的認(rèn)識(shí),證明等待用戶輸入的命令并不是以回車符作為終止輸入的信號(hào)。

 

進(jìn)一步思考一下,眾所周知, set /p 首行=<1.txt 能獲取 1.txt 第一行,那么對(duì)含有大量 set /p 的語(yǔ)塊進(jìn)行重定向,又是什么結(jié)果呢?

 

1.  

@echo off

2.  

(for /l %%a in (1 1 10) do set /p .%%a=)<%0

3.  

set.

4.  

pause

 

可以看到,通過(guò) set /p 配合重定向,能夠把文本每一行都設(shè)為變量值,這是全新的技巧,更重要的是,這是一種全新的遍歷文本的方式,它相當(dāng)于不跳過(guò)空行的 for until ,這與 for /f 的skip 參數(shù)相映成趣,而且還對(duì)特殊字符有極佳的兼容性。不過(guò)有得必有失,使用 set /p 賦值時(shí),變量長(zhǎng)度不能超過(guò) 1024 字節(jié),所以局限了這個(gè)技巧的適用范圍。

 

激動(dòng)之余,又產(chǎn)生了兩個(gè)疑惑:

1、set /p 是以什么為依據(jù)斷行

2、當(dāng)循環(huán)數(shù)大于文本行數(shù)時(shí),為什么沒(méi)有停頓下來(lái)等待用戶輸入

 

和寒夜版主一起做了幾個(gè)試驗(yàn),證明無(wú)論是單純的 0D 回車符或者 0A 換行符都無(wú)法實(shí)現(xiàn)平時(shí)在 cmd 窗口中敲回車結(jié)束 set /p 輸入的效果,必須出現(xiàn)連續(xù)的一組 0D 0A 才能夠終止對(duì)一個(gè) set /p 的輸入。關(guān)于終止 set /p 輸入的“特征碼”,25 樓的 mxxcgzxxx 提出了更合理的猜想:0D 0A 和 0A 0D 這兩種組合都能起到終止 set /p 輸入的作用。

(25樓鏈接:

http://bbs.bathome.net/viewthread.php?tid=13327&page=2&fromuid=30406#pid86638)

 

而第二個(gè)問(wèn)題,繞了半天彎子終于得到一個(gè)比較合理的猜測(cè):當(dāng)重定向的輸入被前面執(zhí)行的命令取用完的時(shí)候,剩下的就是從空設(shè)備的輸入,也就是 set /p .5=

 

1.   

(set /p .a=

2.   

set /p .b=)<只有一行的文件.txt

3.   

set.[/code]其作用相當(dāng)于:[code]set /p .a=<只有一行的文件.txt

4.   

::取首行

5.   

set /p .b=<nul

6.   

::從空設(shè)備獲取輸入,等于無(wú)輸入

7.   

set.

8.   

::顯示以.開(kāi)頭的變量

 

通過(guò)這個(gè)猜測(cè)和其他一些命令接收重定向輸入時(shí)表現(xiàn)出的特性衍生出一個(gè)推測(cè),那就是 cmd 在接受重定向輸入到命令的時(shí)候,也許是一個(gè)字符一個(gè)字符順序傳遞給語(yǔ)塊\語(yǔ)句的,那些能夠接受重定向輸入的命令會(huì)自發(fā)地從中獲取輸入,直到命令自行關(guān)閉輸入句柄為止。

 

這可以理解為cmd中出現(xiàn)重定向輸入的時(shí)候,輸入中的字符在排隊(duì)等候被命令依次提走,一直到無(wú)字符可提的時(shí)候,重定向輸入的來(lái)源就成為了一個(gè)空設(shè)備 nul。

 

好比一個(gè)旅行團(tuán)在打車,出現(xiàn)愿意載客的出租車時(shí),隊(duì)伍就有序地依次上車,一輛車客滿后就再等下一輛(旅行團(tuán)并不知道當(dāng)前這輛車何時(shí)客滿,他們只需要機(jī)械地讓排頭的人上車、直到司機(jī)喊停為止),最終所有人都打車走光,這時(shí)候新來(lái)的出租車就找不到客人了,所以空車離開(kāi)時(shí)當(dāng)然還是空車。

 

當(dāng)然有些命令是以任意合法字符或者固定字符來(lái)判定何時(shí)結(jié)束輸入的,比如choice、set /p和pause,這就很有利用的價(jià)值。

 

此處僅以 set /p 舉幾個(gè)例子:

 

1.   

@echo off

2.   

set /p line=要獲取的行所在行數(shù):

3.   

(for /l %%a in (1 1 %line%) do set /p 內(nèi)容=)<a.txt

4.   

set 內(nèi)容

5.   

::獲取指定行內(nèi)容的新方法,由于無(wú)需遍歷整個(gè)文本,要獲取的行位置靠前的情況下有很大優(yōu)勢(shì)

 

1.    

@echo off

2.    

(for /l %%a in (1 1 100) do set /p .%%a=)<%0

3.     
4.    

::不跳過(guò)空行賦值,但是 tmplinshi 版主的測(cè)試結(jié)果標(biāo)明這中方法比常規(guī)辦法稍慢,它只在某些場(chǎng)合有優(yōu)勢(shì)。

(5樓鏈接:

http://bbs.bathome.net/viewthread.php?tid=13327&page=1&fromuid=30406#pid86516)

 

1.    

@echo off&setlocal enabledelayedexpansion

2.     
3.    

(for /l %%a in (1 1 5) do (

4.    

    if not defined .!n! set /a n+=1

5.    

    set /p .!n!=

6.    

))<%0

7.    

::當(dāng)然也同樣可以跳過(guò)空行只將前N行賦值

8.     
9.    

@echo off

10.      

(for /l %%a in (1 1 7) do (

11.      

    pause

12.      

    set /p echo=

13.      

    echo !echo!

14.      

)<%0

15.      

::去除每行行首第一個(gè)任意字符的另一種方法,如果不計(jì)較效率的話,用choice可以去除指定字符

 

1.     

@echo off

2.     

(for /l %%a in (1 2 7) do (

3.     

    set /a a=1,b=2

4.     

    set /p a=

5.     

    set /p b=

6.     

    if !a!==!b! echo 相等

7.     

)<%0

8.     

::以兩行為周期判斷其內(nèi)容是否相等,這比起老方法省下了許多麻煩,比如無(wú)需用 setlocal、endlocal 來(lái)兼容特殊字符

 

1.     

@echo off

2.     

(for %%a in (

3.     

1-關(guān)回顯 2-for循環(huán) 3-循環(huán)內(nèi)容 4-do 4-設(shè)變量 5-輸入 6-查看變量 7-注釋

4.     

) do (

5.     

    set /p .%%a=

6.     

))<%0

7.     

set.

8.     

::可以通過(guò)無(wú)參數(shù)的for來(lái)循環(huán),實(shí)現(xiàn)了以往無(wú)法實(shí)現(xiàn)的效果

9.      
10. 

@echo off&setlocal enabledelayedexpansion

11. 

(for /f "tokens=1* delims=:" %%a in ('findstr /n .* 1.txt') do (

12. 

    set t2=

13. 

    set /p t2=

14. 

    echo;%%b!t2!

15. 

))<2.txt>合并.txt

16. 

::由于可以有兩個(gè)不同的輸入來(lái)源并存,所以雙文本乃至多文本合并就成為輕而易舉的事了

 

無(wú)奈的是,可以分段接受重定向輸入的命令寥寥無(wú)幾,所以暫時(shí)還沒(méi)有想到更多的實(shí)用技巧,還是等待大家來(lái)補(bǔ)充吧。

 

感謝寒夜孤星、mxxcgzxxx、tmplinshi給予指點(diǎn)和共同探討、測(cè)試。

熱門(mén)評(píng)論
最新評(píng)論
發(fā)表評(píng)論 查看所有評(píng)論(0)
昵稱:
表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)