2011-07-08 65 views

回答

14

tl; dr -Filter使用.NET的實現FsRtllsNameInExpression,這是documented on MSDN連同基本的模式匹配信息。由於兼容性原因,該算法不直觀,您應該避免使用此功能。另外,.NET在實現中有許多缺陷。

-Filter不使用由PowerShell中提供的過濾系統 - 即,它不使用通過Get-Help about_Wildcard描述的過濾系統。相反,它將過濾器傳遞給Windows API。因此,過濾的工作方式與其他使用Windows API的其他程序(如cmd.exe)的工作方式相同。

相反,PowerShell使用類似FsRtlIsNameInExpression的算法進行過濾器模式匹配。該算法基於舊的MS-DOS行爲,所以它充滿了爲遺留目的而保留的警告。通常認爲它有三個常見的特殊字符。確切的行爲是複雜的,但它或多或少類似如下:

  • *:匹配任何數量的字符(零包)
  • ?:精確匹配一個字符,但不包括在名稱上期
  • .:如果模式中的最後一段,錨定到文件名的最後一個句點,或者如果它沒有句點,則停留在文件名的末尾;也可以匹配文字週期

只是爲了使事情更加複雜,Windows添加了三個額外的特殊字符,其行爲與舊的MS-DOS特殊字符完全相同。現在爲了說明更靈活的文件系統,原始特殊字符的行爲略有不同。

  • "相當於MS-DOS .(在ntifs.h DOS_DOTANSI_DOS_DOT
  • <相當於MS-DOS ?(在ntifs.h DOS_QMANSI_DOS_QM
  • >相當於MS-DOS *DOS_STARANSI_DOS_STAR in ntifs.h)

不少來源似乎反轉<>。可怕的是,Microsoft confuses them in their .NET implementation,這意味着它們在PowerShell中也被逆轉。此外,從-Filter開始,所有三個兼容性通配符都不可用,如System.IO.Path mistakenly treats "<> as invalid, non-wildcard characters。 (它允許.*?。)這有助於認爲-Filter是不完整,不穩定和錯誤的概念。您可以看到算法on GitHub的.NET(buggy)實現。

對於8.3 compatibility filenames算法的支持,或者稱爲「短」文件名,這更加複雜。 (您可能以前看過它們;它們看起來像這樣:SOMETH~1.TXT)如果文件的完整文件名稱爲其文件名稱匹配,則文件與該模式匹配。 FrankFranchise has more information about this caveat in his answer.

以前鏈接的關於FsRtlIsNameInExpression的MSDN文章有關Windows文件名模式匹配的最新文檔,但它並不特別詳細。有關如何匹配用於MS-DOS以及這會如何影響現代匹配的更全面說明,this MSDN blog article是我找到的最佳源代碼。這裏的基本思想是:

  • 每個文件名正好是11個字節。
    • 的前8個字節存儲文件名的主體中,右填充空格
    • 存儲擴展,右填充空格
  • 字母最後3個字節被轉換爲大寫
  • 字母,數字,空格和一些符號只匹配自己
  • ?匹配任何單個字符,但擴展名中的空格除外
  • .將用空格填充前8個字節的剩餘部分,然後前進到第9個字節(擴展的開始)
  • *將用問號填充當前部分(主體或擴展部分)的剩餘部分,然後前進到下一節(或模式的結尾)

的轉變應該是這樣的:

      11 
User    12345678901 
------------  ----------- 
ABC.TXT  > ABC  TXT 
WILDCARD.TXT > WILDCARDTXT 
ABC.???  > ABC  ??? 
*.*   > ??????????? 
*.   > ???????? 
ABC.   > ABC   

推斷這與現代文件系統的工作充其量是一個直觀的過程。例如,拿一個目錄,如下列:

Name     Compat Name 
----------------------------------------------- 
Apple1.txt   APPLE1 .TXT 
Banana    BANANA . 
Something.txt  SOMETH~1.TXT 
SomethingElse.txt SOMETH~2.TXT 
TXT.exe    TXT  .EXE 
TXT.eexe    TXT~1 .EEX 
Wildcard.txt   WILDCARD.TXT 

我已經做了相當多的這些通配符的測試在Windows 10已經變得非常不一致的結果,特別是DOS_DOT")。如果您從命令提示符自行測試這些內容,則可能需要將其轉義(例如,在cmd.exe中的dir ^>^"^>以模擬MS-DOS *.*)。

*.*     (everything) 
<"<     (everything) 
*     (everything) 
<     Banana 
.     (everything) 
"     (everything) 
*.     Banana 
<"     Banana 
*g.txt    Something.txt 
<g.txt    Something.txt 
<g"txt    (nothing) 
*1.txt    Apple1.txt, Something.txt 
<1.txt    Apple1.txt, Something.txt 
<1"txt    (nothing) 
*xe     TXT.eexe, TXT.exe 
<xe     (nothing) 
*exe    TXT.eexe, TXT.exe 
<exe    TXT.exe 
??????.???   Apple1.txt, Asdf.tx, Banana, TXT.eexe, TXT.exe 
>>>>>>.>>>   Apple1.txt, Asdf.tx, TXT.eexe, TXT.exe 
>>>>>>">>>   Banana 
????????.???  (everything) 
>>>>>>>>.>>>  (everything except Banana) 
>>>>>>>>">>>  Banana 
???????????.???  (everything) 
>>>>>>>>>>>.>>>  (everything except Banana) 
>>>>>>>>>>>">>>  Banana 
??????    Banana 
>>>>>>    Banana 
???????????   Banana 
>>>>>>>>>>>   Banana 
????????????  Banana 
????    (nothing) 
>>>>    (nothing) 
Banana??.   Banana 
Banana>>.   Banana 
Banana>>"   Banana 
Banana????.   Banana 
Banana>>>>.   Banana 
Banana>>>>"   Banana 
Banana.    Banana 
Banana"    Banana 
*txt    Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt 
<txt    Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt 
*t     Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt 
<t     (nothing) 
*txt*    Apple1.txt, Something.txt, SomethingElse.txt, TXT.eexe, TXT.exe, Wildcard.txt 
<txt<    Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt 
*txt<    Apple1.txt, Something.txt, SomethingElse.txt, Wildcard.txt 
<txt*    Apple1.txt, Something.txt, SomethingElse.txt, TXT.eexe, TXT.exe, Wildcard.txt 

注:截至發稿,葡萄酒的匹配算法產量顯著不同的結果,測試這些「陷阱」的時候。經過葡萄酒1.9.6測試。

正如你所看到的,向後兼容的MS-DOS通配符是模糊的和越野車。 Even Microsoft has implemented them incorrectly at least once,目前還不清楚他們目前在Windows中的行爲是否有意爲之。 "的行爲似乎完全是隨機的,我期望最後兩個測試的結果被交換。

+0

我一直在努力的另一種情況是file.txt_backup -filter *。 txt也拿起這 –

+0

所以我在TechNet博客中發現是使用Where-Object子句允許結果的正則表達式過濾 $ pattern ='print \。\ d {1,40} \ z' Get -ChildItem -Path $ folderLocation | Where-Object {$ _。Name -match $ pattern} | ForEach-Object { #process $ _ } –

-3

它們與所有cmdlet的文檔位置相同。在提示符下鍵入:

Get-Help Get-ChildItem 

如果不告訴你足夠的,那麼:

Get-Help Get-ChildItem -Detailed 

或者,如果你真的想在再挖:

Get-Help Get-ChildItem -Full 

編輯:儘管-Detail可以正常工作,因爲PS會自動消除參數名稱的歧義,但它絕對不會傷害到正確的:)

+1

不幸的是,文件系統過濾器語法中沒有任何內容。 :( – Vimes

+0

這些選項對gci-filter沒有任何幫助。 – dstibbe

8

-filter幾乎沒有。

有一點當你做Get-Help Get-ChildItem -full,但我相信你有seen it。 Powershell博客上還有一個post。既沒有舉例說明。

我能找到的最好的例子是this one,它簡單地證明了過濾器是一個字符串,供應商用它返回它將返回的一個子集,它甚至不直接顯示-filter,而是直接使用它。但是,它比其他鏈接略好一點。

但是,由於提供程序在結果返回到cmdlet之前正在執行篩選,因此有一些注意事項。例如,如果我想遞歸地發現,以「test」開頭的所有文件和目錄,我會想入手這款:

Get-ChildItem -filter 'test*' -recurse 

這將返回任何東西之前,過濾當前目錄中的所有結果遞歸。如果我有一個以「test」開頭的目錄,它會遞歸該目錄(因爲提供程序會將它返回給cmdlet),但是沒有其他目錄。

如示例所示,它可以解決某些提供程序中的屬性。在FileSystem提供程序中,您可能只能在目錄或文件名(葉,不是全限定)上使用通配符匹配字符串。

+1

這看起來似乎不是真的--gci-filter'test *'-recurse'確實遞歸到所有文件夾中,包括不以test *,並返回從test *開始的文件,PowerShell 4在Windows 8上執行此操作,PowerShell 2在Server 2003 SP2上執行此操作。 – TessellatingHeckler

3

若要follow upZenexer提到什麼,您應該看到與使用cmd.exe使用相同過濾器會看到的結果相同。這包括你可能不期望的東西,如8.3短文件名。你可以自己測試一下。

使用PowerShell
創建一些示例文件md filtertest | cd
(1..1000) | % { New-item -Name ("aaaaa{0:D6}.txt" -f $_) -ItemType File }
現在打開一個命令提示符並運行
dir /x
dir aaab*

第一個命令顯示的8.3短名稱。第二個匹配一些文件,即使在任何普通名稱中都沒有'b'字符,因爲這些文件在短名稱中包含'b'。

現在您可以翻轉回PowerShell並運行ls -Filter aaab*以再次查看相同的文件。將-Filter字符串傳遞給WinAPI,該文件與8.3短名稱中的'b'匹配,就像cmd.exe中的dir一樣。所以使用-Filter時要小心未知的結果,您可能會與8.3短名稱匹配。

這都假設您的計算機上啓用了8.3短名稱。

相關問題