來源:http://www.cn-dos.net/forum/viewthread.php?tid=21167&fpage=1&highlight=findstr
問題緣起于bsijl一篇關于findstr錯誤過濾的主題[1],當時因為無法找到原因,所以只能推測 /g 開關存在某些問題。
近日,因為編寫一個debuger代碼,再次使用了 findstr/g ,結果遇到了同樣的問題[2]。經過仔細的測試[3]后,發(fā)現(xiàn)是 findstr
特殊的命令行分析機制所引起的問題。略述如下:
1、findstr不同于早期的find,它對參數(shù)的排列有一定的要求,即遵循開關(可省略)、字符串(使用/c開關時省略)、文件名(可通配、可多個、有輸入流時需省略)的順序。
2、開關可以使用引號,所以不能直接以與開關相同的關鍵字進行搜索;文件名含空格時必須用引號。
3、搜索關鍵字的情況和表現(xiàn)就比較復雜,分述如下:
3-1、無論是否使用開關/l或/r以及是否使用引號,關鍵字中的\都會成為轉義字符,所以\\將成為\,\"將使引號失去字符串界定作用;
3-2、搜索關鍵字可加或不加引號,當加引號時其中的\可能會再次轉義。使用開關/l和/r時的轉義結果可能會不同:當使用/r時,所以"\\\\"將成為單個\,"\\"將使關鍵字為空;當使用/l或均不使用時,"\\\\"和"\\"與單個\等價。
3-3、如果關鍵字以單個\結尾,且無引號,則不會被轉義;
而 findstr/g出現(xiàn)的問題,應該與上述內容有關,但其內在機理仍無法透徹理解。不知各位有何高見?
[1]批處理刪除XP輸入法問題!請dos高手解決
http://www.cn-dos.net/forum/search.php?searchid=24472
[2]Test of findstr/v/g
Quote:
E:\Batch\Test>set > envar.out
E:\Batch\Test>findstr /v /g:envar.out envar.out
LOGONSERVER=\\Test
ProgramFiles=C:\Program Files
E:\Batch\Test>findstr /v /i /g:envar.out
envar.out
LOGONSERVER=\\Test
[3]Test of findstr
CODE: [Copy to clipboard]
:: Test of findstr
:: Will Sort - 2006-06-10 - CMDWinXP
@echo off
cls&echo ---- "set>_tfs1.tmp & findstr /v
/g:_tfs1.tmp _tfs1.tmp"
set>_tfs1.tmp & findstr /v /g:_tfs1.tmp
_tfs1.tmp
pause
echo ---- "findstr /v /i /g:_tfs1.tmp _tfs1.tmp"
findstr /v /i /g:_tfs1.tmp _tfs1.tmp
pause
echo ---- "sort /r _tfs1.tmp > _tfs2.tmp &
findstr /v /g:_tfs1.tmp _tfs2.tmp"
sort /r _tfs1.tmp > _tfs2.tmp & findstr /v
/g:_tfs1.tmp _tfs2.tmp
pause
echo ---- "set|findstr /v /g:_tfs1.tmp"
set|findstr /v /g:_tfs1.tmp
pause
cls&echo ---- "dir C:\ /w > _tfs2.tmp & findstr
/v /g:_tfs2.tmp _tfs2.tmp"
dir C:\ /w > _tfs2.tmp & findstr /v /g:_tfs2.tmp
_tfs2.tmp
pause
echo ---- "echo :\ > _tfs2.tmp & findstr /v
/g:_tfs2.tmp _tfs2.tmp"
echo :\ > _tfs2.tmp & findstr /v /g:_tfs2.tmp
_tfs2.tmp
pause
cls&echo ---- "findstr /g:_tfs1.tmp
_tfs1.tmp>_tfs2.tmp & fc _tfs1.tmp _tfs2.tmp"
findstr /g:_tfs1.tmp _tfs1.tmp>_tfs2.tmp & fc
_tfs1.tmp _tfs2.tmp
pause
cls&echo ---- "set|findstr /r "\\\\ \\\\""
set|findstr /r "\\\\ \\\\"
pause
echo ---- "set|findstr /l "\\\\ \\\\""
set|findstr /l "\\\\ \\\\"
pause
cls&echo ---- "echo _tfs1_tmp > _tfs1.tmp &
findstr "/l" "_tfs1.tmp" "_tfs1.tmp""
echo _tfs1_tmp >> _tfs1.tmp & findstr
"_tfs1.tmp" "_tfs1.tmp"
pause
del _tfs?.tmp
[ Last edited by willsort on 2006-6-11 at 18:38 ]
Climbing
金牌會員
『第 2 樓』:
在我的XP上這個結果如何解釋?
d:\work>findstr /v /g:envar.out envar.out
FINDSTR: 搜索字符串太長。
d:\work>findstr /v /g:envar.out envar.out
FINDSTR: 搜索字符串太長。
d:\work>findstr /v /g:envar.out
FINDSTR: 搜索字符串太長。
無奈何
版主
『第 3 樓』:
在我的 XP 下和 willsort 兄 3、的描述相同。這個惱人的結果不知道能不能確定是
FINDSTR 的 BUG ,請朋友們多試一下其它系統(tǒng)的情況??磥黻P鍵字中含有 “\”
字符應該多加小心了。
3742668
版主
『第 4 樓』:
唔,似乎只有當\后面的字符為非字母和非數(shù)字的時候才會出錯。感覺microsoft準備把findstr做成cmd下的正則表達式工具似的,但是又沒有考慮到與其他參數(shù)之間的兼容性,導致最后的結果是畫虎不成反類犬。
另外在某些時候,findstr的查找字符串中包含中文時,需要加上/i參數(shù)才能避免錯誤,具體環(huán)境以及代碼已忘,或許findstr除了正則表達式方面的bug外還存在unicode與ascii轉換的bug。
willsort
版主
『第 5 樓』:
Re Ups:
另外一個問題:
因為開關也允許引號,所以無法以 "/l" 或 "/r"
等與開關相同的文本串作為關鍵字匹配,下面的句式將會出錯:
echo /l /r > test
findstr /l "/r" test
不過,可以使用開關 /c 來強制指定關鍵字:
findstr /l /c:"/r" test
findstr /l /c:/r test
還有一個方法,就是上文提到的 \ 了:
findstr /l \/r test
此外,這個 \ 還可以讓我們的關鍵字中包含引號:
echo /l /r >test
echo "/r" >> test
findstr /l \"/r\" test
最后,修訂和增補頂樓3-2中的一些描述:
3-2、開關/r和開關/l相同,其后的關鍵字均可使用或不使用引號;使用引號時:
3-2-1、"\"和"\\\"等價于引號和其后各個串所各自代表的多個關鍵字;
3-2-2、"\\\\\"和"\\\\\\\"等價于引號加\組成的關鍵字和其他多個關鍵字;
3-2-3、"\\\\\\\\\"等價于引號加\\組成的關鍵字和其他多個關鍵字;
3-2-4、"\ ","\\","\\\ ","\\\\\
","\\\\\\","\\\\\\\ "等價于空;
3-2-5、"\\ ","\\\\"等價于一個\;
3-2-6、"\\\\ ","\\\\\\\\"等價于兩個\;
3-2-7、"\\\\\\ "等價于三個\;
3-2-8、"\\\\\\\\ "等價于四個\;
以上數(shù)據由以下方法測得,測試文件見[1][2],當不使用/r開關與使用開關/l相同,;
type test1.txt | findstr /r "test_key"
test2.xt
[1] Test text of findstr - "test1.txt"
Quote:
/l /r
"/l"
" test1
\" test1
\\" test1
\\\" test1
\\\\" test1
\ test1
\\ test1
\\\ test1
\\\\ test1
[2] Test text of findstr - "test2.txt"
Quote:
" test2
\" test2
\\" test2
\\\" test2
\\\\" test2
\ test2
\\ test2
\\\ test2
\\\\ test2
[ Last edited by willsort on 2006-6-11 at 18:25 ]
220110
版主
『第 6 樓』:
Quote:
3-2、開關/r和開關/l相同,其后的關鍵字均可使用或不使用引號;使用引號時:
3-2-1、"\"和"\\\"等價于引號和其后各個串所各自代表的多個關鍵字;
3-2-2、"\\\\\"和"\\\\\\\"等價于引號加\組成的關鍵字和其他多個關鍵字;
3-2-3、"\\\\\\\\\"等價于引號加\\組成的關鍵字和其他多個關鍵字;
3-2-4、"\ ","\\","\\\ ","\\\\\
","\\\\\\","\\\\\\\ "等價于空;
3-2-5、"\\ ","\\\\"等價于一個\;
3-2-6、"\\\\ ","\\\\\\\\"等價于兩個\;
3-2-7、"\\\\\\ "等價于三個\;
3-2-8、"\\\\\\\\ "等價于四個\;
我早前也發(fā)現(xiàn)這規(guī)律存在路徑名上,只是沒深入研究,沒敢貼上來.
我是從"dir .\", " dir ..\" 開始,大家不妨測試下.
willsort
版主
狀態(tài) 離線 『第 7 樓』:
Re 220110:
UNC 路徑名中 \ 的解析與 findstr
關鍵字是不同的,它只有界定目錄的作用,而沒有轉義字符的作用。
另外,findstr /v ^%var%$ test.txt 語句中,如果test.txt最后一行就是要匹配的%var%,且該行不為空,則不能過濾最后一行的內容,似乎是分行標志識別出了錯
更多建議: