我希望我的 PowerShell 脚本打印如下内容:
Enabling feature XYZ......Done
脚本看起来像这样:
Write-Output "Enabling feature XYZ......."
Enable-SPFeature...
Write-Output "Done"
但是 Write-Output
总是在最后打印一个新行,所以我的输出不在一行上。有没有办法做到这一点?
Write-Host -NoNewline "Enabling feature XYZ......."
不幸的是,正如在几个答案和评论中所指出的,Write-Host
可能很危险,不能通过管道传输到其他进程,并且 Write-Output
没有 -NoNewline
标志。
但是这些方法是显示进度的“*nix”方式,“PowerShell”的方式似乎是 Write-Progress
:它在 PowerShell 窗口顶部显示一个带有进度信息的栏,从 PowerShell 3.0 开始可用, see manual 了解详情。
# Total time to sleep
$start_sleep = 120
# Time to sleep between each notification
$sleep_iteration = 30
Write-Output ( "Sleeping {0} seconds ... " -f ($start_sleep) )
for ($i=1 ; $i -le ([int]$start_sleep/$sleep_iteration) ; $i++) {
Start-Sleep -Seconds $sleep_iteration
Write-Progress -CurrentOperation ("Sleep {0}s" -f ($start_sleep)) ( " {0}s ..." -f ($i*$sleep_iteration) )
}
Write-Progress -CurrentOperation ("Sleep {0}s" -f ($start_sleep)) -Completed "Done waiting for X to finish"
并以 OP 为例:
# For the file log
Write-Output "Enabling feature XYZ"
# For the operator
Write-Progress -CurrentOperation "EnablingFeatureXYZ" ( "Enabling feature XYZ ... " )
Enable-SPFeature...
# For the operator
Write-Progress -CurrentOperation "EnablingFeatureXYZ" ( "Enabling feature XYZ ... Done" )
# For the log file
Write-Output "Feature XYZ enabled"
虽然它可能不适用于您的情况(因为您正在向用户提供信息输出),但请创建一个可用于附加输出的字符串。当需要输出它时,只需输出字符串。
当然忽略这个例子在你的情况下很愚蠢,但在概念上很有用:
$output = "Enabling feature XYZ......."
Enable-SPFeature...
$output += "Done"
Write-Output $output
显示:
Enabling feature XYZ.......Done
Write-Output
仍会产生额外的换行符。合理的解决方法,但不是解决方案。
要写入文件,您可以使用字节数组。以下示例创建一个空的 ZIP 文件,您可以将文件添加到其中:
[Byte[]] $zipHeader = 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
[System.IO.File]::WriteAllBytes("C:\My.zip", $zipHeader)
或使用:
[Byte[]] $text = [System.Text.Encoding]::UTF8.getBytes("Enabling feature XYZ.......")
[System.IO.File]::WriteAllBytes("C:\My.zip", $text)
是的,因为其他答案有状态,它不能用 Write-Output 来完成。在 PowerShell 失败的地方,转向 .NET,这里甚至有几个 .NET 答案,但它们比它们需要的更复杂。
只需使用:
[Console]::Write("Enabling feature XYZ.......")
Enable-SPFeature...
Write-Output "Done"
它不是最纯粹的 PowerShell,但它可以工作。
Write-Host
,除了人们不会期望它。
在 PowerShell 中似乎没有办法做到这一点。以前的所有答案都不正确,因为它们的行为方式与 Write-Output
的行为方式不同,但更像 Write-Host
,但无论如何都没有这个问题。
关闭解决方案似乎将 Write-Host
与 -NoNewLine
参数一起使用。您不能通过管道处理这通常是一个问题,但有一种方法可以覆盖此函数,如 Write-Host => Export to a file 中所述,因此您可以轻松地使其接受输出文件的参数。这还远不是一个好的解决方案。使用 Start-Transcript
这更有用,但该 cmdlet 在本机应用程序中存在问题。
Write-Output
在一般情况下根本无法满足您的需求。
我遇到的问题是,在使用 PowerShell v2 时,Write-Output 实际上对输出进行了换行,至少到标准输出。我试图将 XML 文本写入标准输出但没有成功,因为它会在字符 80 处被硬包装。
解决方法是使用
[Console]::Out.Write($myVeryLongXMLTextBlobLine)
这在 PowerShell v3 中不是问题。写输出似乎在那里正常工作。
根据调用 PowerShell 脚本的方式,您可能需要使用
[Console]::BufferWidth =< length of string, e.g. 10000)
在您写入标准输出之前。
shuffler 的答案是正确的。换一种说法:不是使用数组形式将值传递给 Write-Output,
Write-Output "Parameters are:" $Year $Month $Day
或多次调用 Write-Output 的等效项,
Write-Output "Parameters are:"
Write-Output $Year
Write-Output $Month
Write-Output $Day
Write-Output "Done."
首先将您的组件连接成一个字符串变量:
$msg="Parameters are: $Year $Month $Day"
Write-Output $msg
这将防止由多次调用 Write-Output(或 ARRAY FORM)引起的中间 CRLF,但当然不会抑制 Write-Output commandlet 的最终 CRLF。为此,您必须编写自己的命令行开关,使用此处列出的其他复杂解决方法之一,或者等到 Microsoft 决定支持 Write-Output 的 -NoNewline
选项。
您希望向控制台提供文本进度表(即“....”)而不是写入日志文件,也应该通过使用 Write-Host 来满足。您可以通过将 msg 文本收集到一个变量中以写入日志并使用 Write-Host 向控制台提供进度来完成这两个任务。可以将此功能组合到您自己的命令行开关中,以实现最大程度的代码重用。
Write-Output
仍然产生了一个额外的换行符,您只是看不到它,因为它是最后写入的内容。合理的解决方法,但不是解决方案。可能有一些东西消耗了无法处理尾随换行符的结果输出。
我作弊了,但我相信这是满足所有要求的唯一答案。也就是说,这避免了尾随的 CRLF,同时为其他操作提供了一个完成的地方,并在必要时正确地重定向到 stdout。
$c_sharp_source = @"
using System;
namespace StackOverflow
{
public class ConsoleOut
{
public static void Main(string[] args)
{
Console.Write(args[0]);
}
}
}
"@
$compiler_parameters = New-Object System.CodeDom.Compiler.CompilerParameters
$compiler_parameters.GenerateExecutable = $true
$compiler_parameters.OutputAssembly = "consoleout.exe"
Add-Type -TypeDefinition $c_sharp_source -Language CSharp -CompilerParameters $compiler_parameters
.\consoleout.exe "Enabling feature XYZ......."
Write-Output 'Done.'
pwsh
(powershell 核心)中,Add-Type 没有 -CompilerParameters
选项,但您可以对其他语言执行相同操作:python3 -c "import sys; print(sys.argv[1], end='')" "Enabling feature XYZ......."
FrinkTheBrave 响应的简化:
[System.IO.File]::WriteAllText("c:\temp\myFile.txt", $myContent)
Write-Host
很糟糕,是世界的毁灭者,但您可以使用它来向用户显示进度,同时使用 Write-Output
进行记录(不是 OP 要求记录)。
Write-Output "Enabling feature XYZ" | Out-File "log.txt" # Pipe to log file
Write-Host -NoNewLine "Enabling feature XYZ......."
$result = Enable-SPFeature
$result | Out-File "log.txt"
# You could try{}catch{} an exception on Enable-SPFeature depending on what it's doing
if ($result -ne $null) {
Write-Host "complete"
} else {
Write-Host "failed"
}
Write-Progress
。
您根本无法让 PowerShell 省略那些讨厌的换行符……没有脚本或 cmdlet 可以。当然,Write-Host 绝对是无稽之谈,因为您无法从中重定向/管道!
不过,您可以编写自己的 EXE 文件来执行此操作,这就是我在 Stack Overflow 问题 How to output something in PowerShell 中解释的操作。
$host.UI.Write('Enabling feature XYZ.......')
Enable-SPFeature...
$host.UI.WriteLine('Done')
以下将光标放回上一行的开头。您可以将其放置在正确的水平位置(使用 $pos.X 将其横向移动):
$pos = $host.ui.RawUI.get_cursorPosition()
$pos.Y -= 1
$host.UI.RawUI.set_cursorPosition($Pos)
您当前的输出超过 27 个空格,因此 $pos.X = 27 可能有效。
$pos.X
,它可以产生正确的输出。问题是,如果将其通过管道传输到文件,则会出现两条单独的行。
它可能不是非常优雅,但它完全符合 OP 的要求。请注意,ISE 会与 StdOut 混淆,因此不会有输出。为了看到这个脚本工作,它不能在 ISE 中运行。
$stdout=[System.Console]::OpenStandardOutput()
$strOutput="Enabling feature XYZ... "
$stdout.Write(([System.Text.Encoding]::ASCII.GetBytes($strOutput)),0,$strOutput.Length)
Enable-SPFeature...
$strOutput="Done"
$stdout.Write(([System.Text.Encoding]::ASCII.GetBytes($strOutput)),0,$strOutput.Length)
$stdout.Close()
[System.Console]
无法重定向到文件。
使用内联连接的最简单方法——同时改为“写入输出”;例如 2 个制表符(字符串)& 然后是文字/逐字(字符串):
Write-Output ("`t`t" + '${devArg}')
我无论如何都不是专家,但为什么不这样:
Write-Output "hello" | ForEach-Object { $PSItem.Trim() } | Do-Whatever
这保持了流水线语义,但只是在将新行字符传递到流水线中之前修剪换行符,以供您接下来需要做的任何事情。如果那是写入文件,那就这样吧。如果这是写给主机,你可以这样做,但如果你确实写给主机,记得使用 | Write-Host -NoNewline
更新:根据我在下面的评论:“我明白为什么我的答案不起作用了。当管道传输到外部程序时,Powershell 不可避免地会附加一个新行字符作为管道语义的一部分。见:github.com/PowerShell/PowerShell/问题/5974 因此,当我将修剪后的文本传递到管道中时,新行字符将重新出现在输入中。”
在 link in the comments 中,该答案包括:
Write-Output "Some text $( $var.Name )"
这对我来说效果很好。如果您需要 ExpandProperty 来获取 Name 的单个值,则 $( )
不是多余的,否则我的输出是这个而不是解析的值:
@{Name=Name; Address=Address; City=City}.Name
所需的o / p:启用功能XYZ......完成
您可以使用以下命令
$a = "启用功能 XYZ"
写输出“$a......完成”
您必须在引号内添加变量和语句。希望这会有所帮助:)
感谢 Techiegal
你绝对可以做到这一点。 Write-Output 有一个名为“NoEnumerate”的标志,它本质上是相同的。
Write-Output
,它的功能与Write-Host
大不相同。读者在复制/粘贴答案之前应注意这一巨大差异。Write-Host
几乎从来都不是正确答案。这相当于在 Unixland 中执行>/dev/tty
。Write-Progress
在某些情况下可能是合适的,请参见下面的示例。Write-Host
与Write-Information
相同,可作为输出流 6 重定向。因此,您可以将其重定向到作为6>output.txt
的文件。它没有“自己的思想”,只是不是你可以从 Unixland 带来的知识,仅此而已,所以很多人误解了它。