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


145

我希望我的PowerShell脚本打印如下内容:

Enabling feature XYZ......Done

该脚本如下所示:

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

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


Answers:


165

写主机-NoNewline“启用功能XYZ......。”


62
由于OP的示例专门使用Write-Output,因此遭到拒绝Write-Host。读者在复制/粘贴答案之前应注意这一巨大差异。
NathanAldenSr'3

5
我@NathanAldenSr同意,写主机没有帮助,如果你正试图输出到文件等
stevethethread

6
Write-Host几乎永远不是正确的答案。这相当于>/dev/tty在Unixland中进行。
马克·里德

2
Write-Progress在某些情况下可能是合适的,请参见下面的示例。
托马斯

12
投票失败,因为OP的示例专门使用Write-OutputWrite-Output没有-NoNewLine参数。
Slogmeister Extraordinaire

49

不幸的是,正如在一些答案和评论中指出的那样,这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"

3
我认为这是显示状态的最佳解决方案。如果您需要日志或其他东西,则必须使用Write-Output的换行符。
fadanner

1
同意,再加上逐步显示的目的只是“花哨”才能进行实时安装,在日志文件中添加它毫无意义:先打印“开始做某事”,然后“完成某件事”
Thomas

13

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

当然,忽略此示例对您而言很愚蠢,但在概念上很有用:

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

显示:

Enabling feature XYZ.......Done

1
在提供的特定示例中,这可能会起作用,但仍会产生额外的换行符Write-Output。合理的解决方法,但不是解决方案。
Slogmeister Extraordinaire

写输出始终在末尾输出换行符。此cmdlet
无法解决

7
这不是重点,因为在安装此功能后会显示整个输出。
majkinetor

10
我不明白,谁对此问题给了超过1的赞美,因为这不是重点,因为在安装了该功能之后会出现整个输出
maxkoryukov

1
“当然可以忽略这个例子,但在概念上很有用:”
shufler

6

是的,因为其他答案都有状态,所以无法使用Write-Output完成。如果PowerShell发生故障,请转到.NET,这里甚至还有几个.NET答案,但它们比实际需要的要复杂得多。

只需使用:

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

它不是最纯的PowerShell,但可以运行。


5
被否决的原因是它的行为与一样Write-Host,只是人们不会期望它。
JBert

4

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

这是一个了不起的例子!
Peter Mortensen


2

我遇到的问题是,在使用PowerShell v2时,Write-Output实际上使输出换行,至少是对stdout而言。我试图将XML文本写到stdout失败,因为它很难用字符80包裹。

解决方法是使用

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

在PowerShell v3中,这不是问题。写输出似乎在那里正常工作。

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

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

在写到stdout之前。


2
行为类似于Write-Host,但更糟。例如,您无法将其通过管道传输到文件。
majkinetor

2

在PowerShell中似乎无法执行此操作。前面的所有答案都不正确,因为它们的行为方式与Write-Output行为方式不同,但更像Write-Host是没有问题的。

关闭解决方案似乎Write-Host-NoNewLine参数一起使用。您不能通过管道传输这通常是一个问题,但是有一种方法可以覆盖此功能,如Write-Host => Export to a file中所述,因此您可以轻松地使其接受输出文件的参数。这仍然不是一个好的解决方案。有了Start-Transcript这更是可用的,但该cmdlet与本地应用程序的问题。

Write-Output在一般情况下根本无法满足您的需求。


2

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
chwarr

1

您根本无法使PowerShell省略那些讨厌的换行符...没有脚本或cmdlet可以。当然,Write-Host绝对是胡说八道,因为您无法从中重定向/管道传输

不过,您可以编写自己的EXE文件来执行此操作,这就是我在“堆栈溢出”问题中说明的操作方法(如何在PowerShell中输出内容)


2
信息不正确。正如Shay和Jay出色回答的那样,只需将-NoNewline添加为第一个参数。
大卫在HotspotOffice,2013年

2
@DavidatHotspotOffice现在可能就是这种情况,但是当我上次触摸一个无效的Windows框(一年多以前)时,您无法从Write-Host重定向/管道传输。公平的说,我对POSH或.NET没有一点耐心,几个月后我辞职了,回到了Unix领域。有趣
samthebest

3
@DavidatHotspotOffice-实际上,他是正确的。Write-Output没有“ NoNewLine”参数,这是原始问题要问的内容。似乎有一些使用Write-Output的充分理由-所以这个答案很有意义。jsnover.com/blog/2013/12/07/write-host-considered-harmful
James Ruskin

投票不足,因为问题是要求在“ PowerShell中”提供解决方案。编写外部EXE并非“在PowerShell中”。
Slogmeister Extraordinaire

1
@SlogmeisterExtraordinaire在PowerShell中是不可能的,因此我的回答是合理的。您之所以投反对票,是因为您很难过,不得不使用世界上最糟糕的外壳操作系统。
samthebest,2016年

1

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 VARIABLE:

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

这将防止由于多次调用Write-Output(或ARRAY FORM)而导致的中间CRLF,但当然不会抑制Write-Output Commandlet的最终CRLF。为此,您将必须编写自己的Commandlet,使用此处列出的其他复杂解决方法之一,或者等到Microsoft决定支持-NoNewlineWrite-Output选项。

您希望向控制台提供文本进度表(即“ ....”),而不是写入日志文件,也可以通过使用Write-Host来满足。您可以通过将msg文本收集到一个变量中以写入日志,以及使用Write-Host为控制台提供进度来完成。可以将此功能组合到您自己的Commandlet中,以最大程度地重用代码。


我比其他人更喜欢这个答案。如果要调用对象的属性,则不能将其括在引号中,因此我使用了:写输出($ msg = $ MyObject.property +“我想包含的某些文本” + $ Object.property)
Lewis

2
@Lewis当然可以在字符串中包含对象属性!使用$()表达式包围任何变量,例如“ $($ MyObject.Property)我要包含$($ Object.property)的某些文本”
shufler 2015年

在提供的特定示例中,这可能会起作用,但是,仍然会产生额外的换行符Write-Output,您看不到它,因为这是最后编写的内容。合理的解决方法,但不是解决方案。可能有些东西消耗了无法处理尾随换行符的结果输出。
Slogmeister Extraordinaire

1
不正确。该解决方案无法通过单个命令来完成。
majkinetor

这没有解决问题。日志文件输出应显示将要尝试的操作,以便可以查看和跟踪故障。串联无法实现这一点。
durette

0

以下将光标移回上一行的开头。您可以将其放置在正确的水平位置(使用$ pos.X将其向侧面移动):

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

您当前的输出是27个空格,因此$ pos.X = 27可能有效。


这与文件输出无关。
Slogmeister Extraordinaire

它也还不错。如果您这样做$pos.X也可以产生正确的输出。问题是,如果将其通过管道传输到文件,则会显示两行。
majkinetor

0

它可能并不十分优雅,但确实可以满足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()

1
不正确。如果将其放入文件并通过管道传输,则不会显示任何内容。
majkinetor

OP并不要求将文件管道化。是的,[System.Console]不能重定向到文件。
Slogmeister Extraordinaire

0

我作弊,但我相信这是解决所有要求的唯一答案。即,这避免了结尾的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.'

0
$host.UI.Write('Enabling feature XYZ.......')
Enable-SPFeature...
$host.UI.WriteLine('Done')

0

所需的o / p:启用功能XYZ ......完成

您可以使用以下命令

$ a =“启用功能XYZ”

写输出“ $ a ......完成”

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

谢谢Techiegal


写输出最好用于将对象放到管道中。对于文本显示,经常使用Write-Host,最近使用Write-Information写入信息流。
逻辑图

0

这里已经有太多答案了,没有人会在这里向下滚动。无论如何,还有一种解决方案,可以在文本末尾没有换行的情况下写:

带有编码的文件输出:

  # a simple one liner
  "Hello World, in one line" | Out-File -Append -Encoding ascii -NoNewline -FilePath my_file.txt;

  # this is a test to show how it works
  "Hello World".Split(" ") | % { "_ $_ _" | Out-File -Append -Encoding ascii -NoNewline -FilePath my_file.txt; }

控制台输出:

  # a simple one liner
  "Hello World, in one line" | Write-Host -NoNewline;

  # this is a test to show how it works
  "Hello World".Split(" ") | % { "_ $_ _" | Write-Host -NoNewline; }

-3

您绝对可以做到这一点。Write-Output具有一个称为“ NoEnumerate ” 的标志,该标志本质上是相同的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.