如何在PowerShell中输出没有换行符的文本?

我想让我的PowerShell脚本打印如下内容:

Enabling feature XYZ......Done

脚本看起来像这样:

Write-Output "Enabling feature XYZ......."
Enable-SPFeature...
Write-Output "Done"

但是Write-Output总是在末尾打印一个新行,所以我的输出不是在一行上。有办法做到这一点吗?

317913 次浏览
< p > < >之前 Write-Host -NoNewline "启用XYZ功能......." < / PRE > < / p >

要写入文件,可以使用字节数组。下面的示例创建一个空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)

你根本不能让PowerShell省略那些讨厌的换行…没有脚本或cmdlet可以做到这一点。当然,Write-Host绝对是胡说八道,因为你不能从它重定向/管道!

尽管如此,你可以编写自己的EXE文件来完成它,这就是我在Stack Overflow问题如何在PowerShell中输出一些东西中解释的方法。

虽然它在您的情况下可能不起作用(因为您正在向用户提供信息输出),但可以创建一个可以用于附加输出的字符串。当需要输出时,只输出字符串。

当然,忽略这个例子在你的情况下是愚蠢的,但在概念上是有用的:

$output = "Enabling feature XYZ......."
Enable-SPFeature...
$output += "Done"
Write-Output $output

显示:

Enabling feature XYZ.......Done

FrinkTheBrave的回应是:

[System.IO.File]::WriteAllText("c:\temp\myFile.txt", $myContent)

我遇到的问题是Write-Output在使用PowerShell v2时实际上是换行输出,至少是stdout。我试图编写一个XML文本到标准输出,但没有成功,因为它将在字符80处被硬包装。

解决办法是使用

[Console]::Out.Write($myVeryLongXMLTextBlobLine)

这在PowerShell v3中不是一个问题。Write-Output似乎工作正常。

根据调用PowerShell脚本的方式,您可能需要使用

[Console]::BufferWidth =< length of string, e.g. 10000)

在写入stdout之前。

下面的操作将把光标移回上一行的开头。这取决于你把它放在正确的水平位置(使用$pos。X来移动它):

$pos = $host.ui.RawUI.get_cursorPosition()
$pos.Y -= 1
$host.UI.RawUI.set_cursorPosition($Pos)

你当前的输出是27个空格,所以pos美元。X = 27可以工作。

shufler的答案是正确的。换一种说法:不是使用ARRAY FORM将值传递给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."

首先将你的组件连接成一个STRING变量:

$msg="Parameters are: $Year $Month $Day"
Write-Output $msg

这将防止多次调用Write-Output(或ARRAY FORM)引起的中间CRLF,但当然不会抑制Write-Output命令行的最终CRLF。为此,您必须编写自己的命令集,使用这里列出的其他复杂的变通方法之一,或者等待微软决定支持-NoNewline选项的write - output。

您希望向控制台提供一个文本进度表(例如。“....”),而不是写入日志文件,也应该通过使用Write-Host来满足。您可以通过将msg文本收集到一个变量中以写入日志和使用Write-Host向控制台提供进度来实现这两种方法。此功能可以组合到您自己的命令集中,以实现最大程度的代码重用。

不幸的是,正如在一些回答和评论中指出的那样,Write-Host可能是危险的,不能被输送到其他进程,而且Write-Output没有-NoNewline标志。

但这些方法是“*nix”显示进度的方法,“PowerShell”的方法似乎是Write-Progress:它在PowerShell窗口顶部显示进度信息,从PowerShell 3.0开始可用,详细信息为参见手册

# 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"

它可能不是特别优雅,但它确实满足了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()

在PowerShell中似乎没有办法做到这一点。前面所有的答案都是错误的,因为它们的行为方式与Write-Output不同,而更像Write-Host,后者无论如何都没有这个问题。

close解决方案似乎使用Write-Host-NoNewLine参数。你不能用管道来处理这个问题,但有一种方法可以覆盖这个函数,如Write-Host =>导出到文件中所述,所以你可以很容易地让它接受输出文件的参数。这还远远不是一个好的解决方案。对于Start-Transcript,这更有用,但cmdlet与本机应用程序有问题。

__abc0根本不能做你在一般上下文中需要做的事情。

是的,因为其他答案都有状态,所以不能用Write-Output完成。在PowerShell失败的地方,转向。net,这里甚至有一些。net的答案,但它们比需要的要复杂得多。

只使用:

[Console]::Write("Enabling feature XYZ.......")
Enable-SPFeature...
Write-Output "Done"

它不是最纯粹的PowerShell,但它可以工作。

你完全可以这样做。Write-Output有一个名为“NoEnumerate”的标志,本质上是相同的东西。

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"
}

我作弊了,但我相信这是唯一能满足所有要求的答案。也就是说,这避免了尾随CRLF,同时为其他操作提供了完成的空间,并在必要时正确地重定向到标准输出。

$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.'
$host.UI.Write('Enabling feature XYZ.......')
Enable-SPFeature...
$host.UI.WriteLine('Done')
< p >的o / p: 启用特性XYZ......Done

.

您可以使用以下命令

$a = "启用功能XYZ"

写出输出的“一美元……”

你必须在引号内添加变量和语句。希望这对你有帮助:)

< p >谢谢 Techiegal < / p >

最简单的方法与内联连接-而移动到'写输出'代替;例如:2个制表符(字符串)&然后是一个字面值/字面值(字符串):

Write-Output ("`t`t" + '${devArg}')

无论如何我都不是专家,但为什么不试试这个:


Write-Output "hello" | ForEach-Object {  $PSItem.Trim() } | Do-Whatever

这将维护管道语义,但只是在将新行字符沿管道传递给您接下来需要做的任何事情之前对其进行修饰。如果是写入文件,那就这样吧。如果这是写入到主机,你可以这样做,但如果你确实写入到主机,记得使用| Write-Host -NoNewline

更新:根据我下面的评论:“我知道为什么我的答案行不通了。当连接到外部程序时,Powershell不可避免地将一个新的行字符作为管道语义的一部分。看到这里:github.com/PowerShell/PowerShell/issues/5974因此,当我将经过修剪的文本传递到管道中时,新的行字符将重新出现在输入中。

评论中的链接中,答案包括:

Write-Output "Some text $( $var.Name )"

这对我来说很有效。如果你需要ExpandProperty来获取Name的单个值,$( )不是多余的,否则我的输出是这样的,而不是解析的值:

@{Name=Name; Address=Address; City=City}.Name