Out-File 输出缺少数据行之间的换行符
Out-File output is missing line feeds between lines of data
我正在传递 $users
的数组。
PS C:\> $users | ft
ID DisplayName AdminID first last Password
---- ----------- ------- ----- ---- --------
Axyz Axyz, Bill NBX_Admin Bill Axyz Secret
代码:
$y = @()
$y = "Create Users process. Run started at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
foreach ($x in $users) {
$y += "User $($x.DisplayName) with NNN of $($x.ID)"
}
$y += "Completed at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
$y | Out-File "Log.txt"
$y
现在是一个未格式化的字符串数组。当我在屏幕上输入 $y
时,它看起来很棒。
如果我将它定向到 Format-Table
,它看起来很棒(没有标题)。
当我将它输出到文件并在命令提示符下键入该文件时 (cmd.exe
),它看起来很棒。
但是,当我在记事本中将其拉出时,所有输出都出现在一行中。准确地说,所有数据都在那里,没有丢失任何数据行,但没有 CR/LF,因此当使用 Notepad.exe 查看时,所有数据都显示在文件中的一行中。
由于使用 +=
在每次迭代时重新创建数组,我建议将 ForEach-Object
的输出分配给 -Begin
、-Process
和 -End
部分也使用格式运算符的更常见方法。:
$Log = $users | ForEach-Object -Begin {
"Create Users process. Run started at [{0:MM/dd/yyyy} {0:HH:mm:ss}]" -f (Get-Date)
} -Process {
"User {0} with NNN of {1}" -f $_.DisplayName,$_.ID
} -End {
"Completed at [{0:MM/dd/yyyy} {0:HH:mm:ss}]" -f (Get-Date)
}
$Log | Set-Content "Log.txt"
正如 AdminOfThings 正确指出的:
虽然 $y = @()
将空数组分配给 $y
,但它不会 type-constrain 那个变量,所以 你的下一个赋值 - $y = "Create Users process ..."
- 将变量类型 更改为 string.
- 在后续赋值中简单地使用
+=
而不是 =
就可以避免问题:$y += "Create Users process ..."
.
- 或者,类型约束 变量创建 -
[array] $y = @()
- 即,将类型文字放置在被分配变量的左侧(类似于强制转换) - 也可以避免这个问题。
随后使用 +=
因此执行简单的 字符串连接 而不是所需的逐步构建一个数组,添加的 "lines" 之间没有分隔符。[1]
- 相比之下,如果您按预期使用 数组 ,
Out-File
和 Set-Content
都会自动 在元素之间插入适合平台的换行符[2],在末尾加一个,保存时(在 PSv5+ 中你可以使用 -NoNewline
切换为选择退出)。
也就是说,使用 +=
到 "extend" 数组效率低下,因为 PowerShell 必须在幕后做的是创建一个 new 数组,其中包含鉴于数组是 固定大小 数据结构,旧元素加上新元素。
虽然在循环中使用 +=
到 "extend" 数组的性能损失仅在高迭代次数时才真正重要,但 let 更简洁、方便和高效PowerShell 通过使用 foreach
循环作为 表达式 :
为您 隐式 创建数组
# Initialize the array and assign the first element.
# Due to the type constraint ([array]), the RHS string implicitly becomes
# the array's 1st element.
[array] $y = "Create Users process. Run started at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
# Add the strings output by the foreach loop to the array.
# PowerShell implicitly collects foreach output in an array when
# you use it in as an expression.
$y += foreach ($x in $users)
{
"User $($x.displayname) with NNN of $($x.ID)"
}
# Add the final string to the array.
$y += "Completed at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
# Send the array to a file with Out-File, which separates
# the elements with newlines and adds a trailing one.
# Windows PowerShell:
# Out-File creates UTF-16LE-encoded files.
# Set-Content, which can alternatively be used, creates "ANSI"-encoded files.
# PowerShell Core:
# Both cmdlets create UTF-8-encoded files without BOM.
$y | Out-File "Log.txt"
请注意,您可以类似地使用 for
、if
、do
/ while
/ switch
语句作为表达式.
但是,在所有情况下,从 PowerShell 7.0 开始,这些语句只能作为表达式自身;遗憾的是,将它们用作管道的第一段或将它们嵌入更大的表达式中确实 无效 - 参见 this GitHub issue.
[1] 问题的简单演示:
# The initialization of $y as @() is overridden by $y = 'first'.
PS> $y = @(); $y = 'first'; $y += 'second'; $y
firstsecond # !! $y contains a single string built with string concatenation
因此,您的症状描述与您的代码不一致,因为您应该在所有情况下都看到单行输出字符串(直接打印到屏幕/通过 Format-Table
,发送到文件和 type
-ing 来自 cmd.exe
).
[2] 平台合适的换行反映在[Environment]::NewLine
,在Windows上是"`r`n"
(CRLF),只是"`n"
(LF)在类 Unix 平台上(在 PowerShell Core)。
我正在传递 $users
的数组。
PS C:\> $users | ft ID DisplayName AdminID first last Password ---- ----------- ------- ----- ---- -------- Axyz Axyz, Bill NBX_Admin Bill Axyz Secret
代码:
$y = @()
$y = "Create Users process. Run started at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
foreach ($x in $users) {
$y += "User $($x.DisplayName) with NNN of $($x.ID)"
}
$y += "Completed at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
$y | Out-File "Log.txt"
$y
现在是一个未格式化的字符串数组。当我在屏幕上输入 $y
时,它看起来很棒。
如果我将它定向到 Format-Table
,它看起来很棒(没有标题)。
当我将它输出到文件并在命令提示符下键入该文件时 (cmd.exe
),它看起来很棒。
但是,当我在记事本中将其拉出时,所有输出都出现在一行中。准确地说,所有数据都在那里,没有丢失任何数据行,但没有 CR/LF,因此当使用 Notepad.exe 查看时,所有数据都显示在文件中的一行中。
由于使用 +=
在每次迭代时重新创建数组,我建议将 ForEach-Object
的输出分配给 -Begin
、-Process
和 -End
部分也使用格式运算符的更常见方法。:
$Log = $users | ForEach-Object -Begin {
"Create Users process. Run started at [{0:MM/dd/yyyy} {0:HH:mm:ss}]" -f (Get-Date)
} -Process {
"User {0} with NNN of {1}" -f $_.DisplayName,$_.ID
} -End {
"Completed at [{0:MM/dd/yyyy} {0:HH:mm:ss}]" -f (Get-Date)
}
$Log | Set-Content "Log.txt"
正如 AdminOfThings 正确指出的:
虽然
$y = @()
将空数组分配给$y
,但它不会 type-constrain 那个变量,所以 你的下一个赋值 -$y = "Create Users process ..."
- 将变量类型 更改为 string.- 在后续赋值中简单地使用
+=
而不是=
就可以避免问题:$y += "Create Users process ..."
. - 或者,类型约束 变量创建 -
[array] $y = @()
- 即,将类型文字放置在被分配变量的左侧(类似于强制转换) - 也可以避免这个问题。
- 在后续赋值中简单地使用
随后使用
+=
因此执行简单的 字符串连接 而不是所需的逐步构建一个数组,添加的 "lines" 之间没有分隔符。[1]- 相比之下,如果您按预期使用 数组 ,
Out-File
和Set-Content
都会自动 在元素之间插入适合平台的换行符[2],在末尾加一个,保存时(在 PSv5+ 中你可以使用-NoNewline
切换为选择退出)。
- 相比之下,如果您按预期使用 数组 ,
也就是说,使用 +=
到 "extend" 数组效率低下,因为 PowerShell 必须在幕后做的是创建一个 new 数组,其中包含鉴于数组是 固定大小 数据结构,旧元素加上新元素。
虽然在循环中使用 +=
到 "extend" 数组的性能损失仅在高迭代次数时才真正重要,但 let 更简洁、方便和高效PowerShell 通过使用 foreach
循环作为 表达式 :
# Initialize the array and assign the first element.
# Due to the type constraint ([array]), the RHS string implicitly becomes
# the array's 1st element.
[array] $y = "Create Users process. Run started at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
# Add the strings output by the foreach loop to the array.
# PowerShell implicitly collects foreach output in an array when
# you use it in as an expression.
$y += foreach ($x in $users)
{
"User $($x.displayname) with NNN of $($x.ID)"
}
# Add the final string to the array.
$y += "Completed at $('[{0:MM/dd/yyyy} {0:HH:mm:ss}]' -f (Get-Date))"
# Send the array to a file with Out-File, which separates
# the elements with newlines and adds a trailing one.
# Windows PowerShell:
# Out-File creates UTF-16LE-encoded files.
# Set-Content, which can alternatively be used, creates "ANSI"-encoded files.
# PowerShell Core:
# Both cmdlets create UTF-8-encoded files without BOM.
$y | Out-File "Log.txt"
请注意,您可以类似地使用 for
、if
、do
/ while
/ switch
语句作为表达式.
但是,在所有情况下,从 PowerShell 7.0 开始,这些语句只能作为表达式自身;遗憾的是,将它们用作管道的第一段或将它们嵌入更大的表达式中确实 无效 - 参见 this GitHub issue.
[1] 问题的简单演示:
# The initialization of $y as @() is overridden by $y = 'first'.
PS> $y = @(); $y = 'first'; $y += 'second'; $y
firstsecond # !! $y contains a single string built with string concatenation
因此,您的症状描述与您的代码不一致,因为您应该在所有情况下都看到单行输出字符串(直接打印到屏幕/通过 Format-Table
,发送到文件和 type
-ing 来自 cmd.exe
).
[2] 平台合适的换行反映在[Environment]::NewLine
,在Windows上是"`r`n"
(CRLF),只是"`n"
(LF)在类 Unix 平台上(在 PowerShell Core)。