我有以下愚蠢的 PowerShell 腳本:
$username = 'rny'
$null = mkdir "c:\Users\$username\YYY"
$null = mkdir "c:\Users\$username\YYY\TODO"
$null = mkdir "c:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc"
$files = "C:\Users\$username\one-two-three-four.sql.wxyz",
"C:\Users\$username\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz",
"C:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz"
foreach ($file in $files) {
$null = new-item $file
}
Get-ChildItem . -errorAction silentlyContinue -recurse -filter *.wxyz | select-object fullName
foreach ($file in $files) {
remove-item -literalPath $file
}
rmdir "c:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc"
rmdir "c:\Users\$username\YYY\TODO"
rmdir "c:\Users\$username\YYY"
當我執行它時,get-childItem ... | select-object管道的輸出被截斷:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\an...
特別注意最后一行。這種行為在 SuperUser 的其他地方被注意到,并且接受的答案是將輸出通過管道傳輸到format-tablewith 中-autoSize。到現在為止還挺好。
$files但是,如果我像這樣評論陣列分配中的第二個檔案
$files = "C:\Users\$username\one-two-three-four.sql.wxyz",
# "C:\Users\$username\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz",
"C:\Users\$username\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz"
輸出不再被截斷:
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz
這讓我感到困惑,因為被截斷的檔案的名稱現在完全可見,我對此沒有任何解釋。
那么,究竟是什么原因導致檔案在一種情況下被截斷而不是在另一種情況下?
uj5u.com熱心網友回復:
Select-Object這與本身并沒有太大關系- 它更多地與 PowerShell 如何將值轉換為字串表示形式有關,特別是在這種情況下,當它在控制臺上顯示來自 cmdlet 的未捕獲輸出時,它是如何做到這一點的。
PowerShell(Windows和Core)有一堆預配置的“視圖”,它們定義了一些內置型別如何呈現 - 例如,它們是否使用Format-List或Format-Table,要顯示的屬性,以及在表格的情況下,顯示每列的寬度 -請參閱about_Format.ps1xml。
對于其他型別,PowerShell 嘗試即時做出最佳猜測。為此,它會等待輸入的前 N ??個專案到達,以決定要應用的格式化規則。我找不到任何明確的檔案說明 PowerShell 等待多少專案,所以這可能是一個很好的后續問題:-)。
您顯然可以通過為Format-Table和傳遞格式引數來覆寫這些默認值Format-List。
在您的情況下,頂級腳本已接收到包含PSCustomObject物件陣列的管道輸出(即來自 的輸出Select-Object),并決定將它們顯示在帶有FullName屬性列的表中。
示例 1
在您的第一個示例中,它查看了前兩個 PSCustomObject 專案并決定將FullName列設為 54 個字符寬,因為這是 的長度C:\Users\rny\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz,第三個專案被截斷為相同的寬度(如果您包括...),因為它沒有被包括在內在列寬的決策程序中。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-11_29_abcdefghijklmnop.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\an...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 54 characters
示例 2
在您的第二個示例中,PowerShell 在前幾個 PSCustomObjects 中看到最長的 FullName 屬性,C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz因此使用 70 的列寬。
FullName
--------
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^| 70 characters
示例 3
最后,如果您按照@notjustme 在評論中的建議進行操作并添加-ExpandProperty FullName到Select-Object您得到一個string值陣列而不是一個PSCustomObjects 陣列,這就是為什么您可能會看到 PowerShell 應用不同的格式規則 - 例如,您不會得到一個FullName標題,因為values 是字串而不是具有屬性的物件,它使用Format-List而不是Format-Table.
C:\Users\rny\one-two-three-four.sql.wxyz
C:\Users\rny\YYY\TODO\2021-12-22_Foo-bar-baz-etc\another-filename.wxyz
uj5u.com熱心網友回復:
為mclayton 的有用答案添加一些背景:
具體來說,您會看到臭名昭著的 300 毫秒的效果。Format-Table格式化中內置的延遲,PowerShell隱式應用于具有 4 個或更少屬性且沒有與之關聯的顯式格式化資料的 .NET 型別的實體。
有關詳細資訊,請參閱此答案(在同一問題的不同癥狀的背景關系中給出,即意外的輸出排序),但它的短處是:延遲用于從接收到的特定屬性值推斷合適的列寬延遲期。
這意味著在 300 毫秒之后收到具有屬性值的物件。如果它們的值恰好比延遲期間接收到的值中的最寬值更寬,則延遲可能會在其列顯示中被截斷。
具體來說,您的癥狀意味著在延遲期內僅收到前兩個物件,并且兩個屬性值中的較長時間然后鎖定在列寬中;稍后收到第三個物件時,列寬已被鎖定,較長的值被截斷(...在 Windows PowerShell(3 個.字符)和…PowerShell(Core)7 (單個字符)中用尾隨表示)
避免截斷的唯一方法是知道最大值。提前列寬并將其傳遞給顯式 Format-Table呼叫 -
值得注意的是,這可以防止將輸出用作 data。見下文。
這是一個引發問題的簡單方法:
注意:Select-Object下面的呼叫不是嚴格需要的,但為了與問題對稱而提供。
# Create blocks of two objects with strings of different length in their
# .Prop value: 10 chars. vs. 100 chars.
$count = 10000 # How often to repeat each object in a row.
$objs =
(, [pscustomobject] @{ Prop = ('x' * 10) } * $count)
(, [pscustomobject] @{ Prop = ('y' * 100) } * $count)
# Depending on the value of $count - which translates into how
# long it takes until the second block of objects starts emitting -
# truncation will occur or not.
$objs | Select-Object Prop
對于10,000物件塊,我確實看到了截斷:第一個塊(具有短屬性值)需要足夠長的時間來鎖定顯示列的寬度,從而導致第二個塊中的物件被截斷:
Prop
----
xxxxxxxxxx
...
yyyyyyyyy… # <- truncated, because width 10 was locked in during the delay
...
為防止截斷,請將計算屬性傳遞給Format-Table指定最大值。寬度:
$objs | Select-Object Prop | Format-Table @{ n='Prop'; e='Prop'; width = 100 }
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/412557.html
標籤:
