Wie gebe ich Text ohne Zeilenumbruch in PowerShell aus?


145

Ich möchte, dass mein PowerShell-Skript etwa Folgendes druckt:

Enabling feature XYZ......Done

Das Skript sieht ungefähr so ​​aus:

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

Druckt aber Write-Outputimmer eine neue Zeile am Ende, damit meine Ausgabe nicht in einer Zeile steht. Gibt es eine Möglichkeit, dies zu tun?


Antworten:


165

Write-Host -NoNewline "Aktivierungsfunktion XYZ ......."


62
Downvoted, weil das Beispiel des OP speziell verwendet Write-Output, was eine völlig andere Funktion hat als Write-Host. Leser sollten diese große Diskrepanz beachten, bevor sie die Antwort kopieren / einfügen.
NathanAldenSr

5
Ich stimme @NathanAldenSr zu, Write-Host hilft nicht, wenn Sie versuchen, in eine Datei usw.
auszugeben

6
Write-Hostist fast nie die richtige Antwort. Es ist das Äquivalent zu >/dev/ttyUnixland.
Mark Reed

2
Write-Progresskann in einigen Fällen angemessen sein, siehe Beispiel unten.
Thomas

12
Downvoted, weil das Beispiel des OP speziell verwendet Write-Output. Write-Outputhat den -NoNewLineParameter nicht.
Slogmeister Extraordinaire

49

Wie in mehreren Antworten und Kommentaren erwähnt, Write-Hostkann dies leider gefährlich sein und kann nicht an andere Prozesse weitergeleitet werden und Write-Outputhat nicht das -NoNewlineFlag.

Diese Methoden sind jedoch die "* nix" -Methoden zum Anzeigen des Fortschritts. Die "PowerShell" -Methode scheint dies zu sein Write-Progress: Sie zeigt oben im PowerShell-Fenster eine Leiste mit Fortschrittsinformationen an, die ab PowerShell 3.0 verfügbar sind ( siehe Handbuch für) Einzelheiten.

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

Und um das Beispiel des OP zu nehmen:

# 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
Ich denke, dies ist die beste Lösung, um den Status anzuzeigen. Wenn Sie ein Protokoll oder etwas anderes benötigen, müssen Sie mit dem Zeilenumbruch von Write-Output leben.
Fadanner

1
Einverstanden, und der Punkt der progressiven Anzeige ist nur "ausgefallen" für die Live-Installation. Es macht keinen Sinn, sie in Protokolldateien zu haben: Drucken Sie "etwas anfangen" und dann "etwas tun"
Thomas

13

In Ihrem Fall funktioniert dies möglicherweise nicht (da Sie dem Benutzer eine informative Ausgabe bereitstellen). Erstellen Sie jedoch eine Zeichenfolge, mit der Sie die Ausgabe anhängen können. Wenn es Zeit ist, es auszugeben, geben Sie einfach den String aus.

Ignorieren Sie natürlich, dass dieses Beispiel in Ihrem Fall albern, aber im Konzept nützlich ist:

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

Anzeigen:

Enabling feature XYZ.......Done

1
Dies funktioniert möglicherweise in dem angegebenen Beispiel, es wird jedoch noch ein zusätzlicher Zeilenvorschub von erzeugt Write-Output. Angemessene Problemumgehung, aber keine Lösung.
Slogmeister Extraordinaire

Write-Output gibt am Ende immer eine neue Zeile aus. Daran führt kein Weg vorbei mit diesem Cmdlet
Shufler

7
Dies ist nicht der Punkt, da die gesamte Ausgabe nach der Installation der Funktion angezeigt wird.
Majkinetor

10
Ich verstehe nicht, wer mehr als 1 Upwote zu dieser Frage gibt, weil dies nicht der Punkt ist, da die gesamte Ausgabe NACH der Installation der Funktion erscheint
maxkoryukov

1
"Natürlich ignorieren, dass dieses Beispiel in Ihrem Fall albern, aber im Konzept nützlich ist:"
Shufler

6

Ja, da andere Antworten Zustände haben, kann dies nicht mit Write-Output durchgeführt werden. Wenn PowerShell fehlschlägt, wenden Sie sich an .NET. Hier gibt es sogar einige .NET-Antworten, die jedoch komplexer sind als erforderlich.

Benutz einfach:

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

Es ist nicht die reinste PowerShell, aber es funktioniert.


5
Downvoted, weil sich das genauso verhält Write-Host, außer dass die Leute es nicht erwarten.
JBert

4

Zum Schreiben in eine Datei können Sie ein Byte-Array verwenden. Im folgenden Beispiel wird eine leere ZIP-Datei erstellt, zu der Sie Dateien hinzufügen können:

[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)

Oder verwenden Sie:

[Byte[]] $text = [System.Text.Encoding]::UTF8.getBytes("Enabling feature XYZ.......")
[System.IO.File]::WriteAllBytes("C:\My.zip", $text)

Das ist ein großartiges Beispiel!
Peter Mortensen

2

Eine Vereinfachung der Antwort von FrinkTheBrave:

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

Dies beantwortet die Frage überhaupt nicht.
NathanAldenSr

2
Aber genau das habe ich gesucht und was ich vom Titel der Frage erwartet habe.
Patrick Roocks

2

Das Problem, auf das ich gestoßen bin, war, dass Write-Output bei Verwendung von PowerShell v2 tatsächlich Zeilenumbrüche verursacht, zumindest bei Standardausgabe. Ich habe versucht, einen XML-Text ohne Erfolg in stdout zu schreiben, da er bei Zeichen 80 schwer verpackt werden würde.

Die Problemumgehung war zu verwenden

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

Dies war in PowerShell v3 kein Problem. Die Schreibausgabe scheint dort ordnungsgemäß zu funktionieren.

Je nachdem, wie das PowerShell-Skript aufgerufen wird, müssen Sie es möglicherweise verwenden

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

bevor Sie an stdout schreiben.


2
Benimmt sich wie Write-Host, aber am schlimmsten. Sie können es beispielsweise nicht an eine Datei weiterleiten.
Majkinetor

2

In PowerShell scheint dies nicht möglich zu sein. Alle vorherigen Antworten sind nicht korrekt, da sie sich nicht so Write-Outputverhalten, wie sie sich verhalten, sondern eher so, wie Write-Hostsie dieses Problem sowieso nicht haben.

Die Closes-Lösung scheint Write-Hostmit dem -NoNewLineParameter zu arbeiten. Sie können dies nicht weiterleiten, was im Allgemeinen ein Problem darstellt. Es gibt jedoch eine Möglichkeit, diese Funktion zu überschreiben, wie unter Write-Host => Export in eine Datei beschrieben , sodass Sie den Parameter für eine Ausgabedatei problemlos akzeptieren können. Dies ist noch lange keine gute Lösung. Mit Start-Transcriptdieser mehr verwendbar ist, aber das Cmdlet hat Probleme mit nativen Anwendungen.

Write-Outputkann im allgemeinen Kontext einfach nicht das tun, was Sie brauchen.


2

Write-Hostist schrecklich, ein Zerstörer der Welten, aber Sie können es nur verwenden, um einem Benutzer den Fortschritt während Write-Outputder Protokollierung anzuzeigen (nicht, dass das OP um Protokollierung gebeten hat).

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

Abhängig von Ihren Anforderungen an die Anzeige des Fortschritts gibt es auch Write-Progress.
Chwarr

1

Sie können PowerShell einfach nicht dazu bringen, diese lästigen Zeilenumbrüche wegzulassen ... Es gibt kein Skript oder Cmdlet, das dies tut. Natürlich ist Write-Host absoluter Unsinn, weil man nicht umleiten / weiterleiten kann!

Trotzdem können Sie Ihre eigene EXE-Datei schreiben, um dies zu tun. Dies habe ich in der Frage zum Stapelüberlauf erläutert. So geben Sie etwas in PowerShell aus .


2
Falsche Angaben. Wie Shay und Jay hervorragend geantwortet haben, fügen Sie einfach -NoNewline als erstes Argument hinzu.
David bei HotspotOffice

2
Vielleicht ist das jetzt bei @DavidatHotspotOffice der Fall, aber als ich das letzte Mal eine Windows-Box (vor über einem Jahr) berührte, die nicht funktionierte, konnte ich nicht von Write-Host umleiten / weiterleiten. Um fair zu sein, ich hatte nicht die geringste Geduld für POSH oder .NET. Ich habe nach ein paar Monaten aufgehört und bin zurück zu Unix Land gegangen. lustig
samthebest

3
@DavidatHotspotOffice - Eigentlich hat er recht. Es gibt kein "NoNewLine" -Argument für Write-Output, worüber die ursprüngliche Frage gestellt wurde. Es gibt anscheinend einige gute Gründe für die Verwendung von Write-Output - daher ist diese Antwort sinnvoll. jsnover.com/blog/2013/12/07/write-host-considered-harmful
James Ruskin

Downvoted, weil die Frage nach einer Lösung "in PowerShell" fragt. Das Schreiben einer externen EXE-Datei ist nicht "In PowerShell".
Slogmeister Extraordinaire

1
@SlogmeisterExtraordinaire In PowerShell ist dies nicht möglich, daher ist meine Antwort vernünftig. Sie stimmen nur ab, weil Sie so traurig sind, dass Sie mit dem schlechtesten Betriebssystem der Welt arbeiten müssen, das die schlechteste Shell der Welt hat.
Samthebest

1

Die Antwort von Shufler ist richtig. Anders ausgedrückt: Anstatt die Werte mit dem ARRAY-FORMULAR an Write-Output zu übergeben,

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

oder das Äquivalent durch mehrere Aufrufe von Write-Output,

Write-Output "Parameters are:"
Write-Output $Year
Write-Output $Month
Write-Output $Day
Write-Output "Done."

Verketten Sie Ihre Komponenten zuerst zu einem STRING VARIABLE:

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

Dies verhindert die Zwischen-CRLFs, die durch mehrmaliges Aufrufen von Write-Output (oder ARRAY FORM) verursacht werden, unterdrückt jedoch natürlich nicht die endgültige CRLF des Write-Output-Commandlets. Dazu müssen Sie Ihr eigenes Commandlet schreiben, eine der anderen hier aufgeführten komplizierten Problemumgehungen verwenden oder warten, bis Microsoft die -NoNewlineOption für Write-Output unterstützt.

Ihr Wunsch, der Konsole eine Textfortschrittsanzeige (dh "....") zur Verfügung zu stellen, anstatt in eine Protokolldatei zu schreiben, sollte auch mit Write-Host erfüllt werden. Sie können beides erreichen, indem Sie den Nachrichtentext in einer Variablen zum Schreiben in das Protokoll sammeln UND mit Write-Host den Fortschritt für die Konsole bereitstellen. Diese Funktionalität kann für die bestmögliche Wiederverwendung von Code in Ihrem eigenen Commandlet kombiniert werden.


Ich bevorzuge diese Antwort gegenüber den anderen. Wenn Sie Eigenschaften von Objekten aufrufen, können Sie sie nicht in Anführungszeichen setzen, also habe ich Folgendes verwendet: Write-Output ($ msg = $ MyObject.property + "Einige Texte, die ich einschließen möchte" + $ Object.property)
Lewis

2
@ Lewis Sie können sicherlich Objekteigenschaften in eine Zeichenfolge aufnehmen! Verwenden Sie den Ausdruck $ (), um eine beliebige Variable zu umgeben, z. B. "$ ($ MyObject.Property) Text, den ich $ ($ Object.property)
einschließen

Dies funktioniert möglicherweise in dem angegebenen Beispiel, aber es wird immer noch ein zusätzlicher Zeilenvorschub von erstellt Write-Output. Sie können ihn einfach nicht sehen, da er als letztes geschrieben wurde. Angemessene Problemumgehung, aber keine Lösung. Möglicherweise verbraucht die resultierende Ausgabe etwas, das den nachfolgenden Zeilenumbruch nicht verarbeiten kann.
Slogmeister Extraordinaire

1
Nicht richtig. Die Lösung kann nicht mit einem einzigen Befehl durchgeführt werden.
Majkinetor

Dies geht nicht auf die Frage ein. Die Ausgabe der Protokolldatei sollte den Vorgang anzeigen, der versucht werden sollte, damit der Fehler erkannt und verfolgt werden kann. Verkettung erreicht das nicht.
Durette

0

Im Folgenden wird der Cursor wieder am Anfang der vorherigen Zeile platziert. Es liegt an Ihnen, es in der richtigen horizontalen Position zu platzieren (mit $ pos.X seitwärts zu bewegen):

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

Ihre aktuelle Ausgabe ist 27 Leerzeichen höher , sodass $ pos.X = 27 möglicherweise funktioniert.


Dies hat nichts mit der Dateiausgabe zu tun.
Slogmeister Extraordinaire

Es ist auch nicht so schlimm. Es kann die richtige Ausgabe erzeugen, wenn Sie dies $pos.Xauch tun . Das Problem ist, dass beim Weiterleiten an eine Datei zwei separate Zeilen angezeigt werden.
Majkinetor

0

Es mag nicht besonders elegant sein, aber es macht genau das, was OP verlangt hat. Beachten Sie, dass die ISE mit StdOut in Konflikt gerät, sodass keine Ausgabe erfolgt. Damit dieses Skript funktioniert, kann es nicht innerhalb der ISE ausgeführt werden.

$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
Nicht richtig. Wenn Sie das in eine Datei einfügen und deren Ausgabe weiterleiten, wird nichts angezeigt.
Majkinetor

Das Weiterleiten an eine Datei wurde vom OP nicht angefordert. Und ja, [System.Console]kann nicht in eine Datei umgeleitet werden.
Slogmeister Extraordinaire

0

Ich habe betrogen, aber ich glaube, dies ist die einzige Antwort, die alle Anforderungen erfüllt. Dies vermeidet nämlich die nachfolgende CRLF, bietet einen Platz für den anderen Vorgang, der in der Zwischenzeit abgeschlossen werden kann, und leitet bei Bedarf ordnungsgemäß zu stdout um.

$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

Gewünschtes O / P: Aktivieren der Funktion XYZ ...... Fertig

Sie können den folgenden Befehl verwenden

$ a = "Funktion XYZ aktivieren"

Schreibausgabe "$ a ...... Done"

Sie müssen Variablen und Anweisungen in Anführungszeichen setzen. hoffe das ist hilfreich :)

Danke Techiegal


Write-Output wird bevorzugt, um Objekte in die Pipeline zu stellen. Für die Textanzeige wird häufig Write-Host verwendet, und in jüngerer Zeit werden Write-Information zum Schreiben in den Informationsstrom verwendet.
Logisches Diagramm

0

Hier gibt es bereits so viele Antworten, dass hier niemand nach unten scrollen wird. Auf jeden Fall gibt es auch eine Lösung, um Text ohne neue Zeile am Ende zu schreiben:

Dateiausgabe mit Codierung:

  # 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; }

Konsolenausgabe:

  # 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

Sie können dies absolut tun. Write-Output hat ein Flag namens " NoEnumerate ", das im Wesentlichen dasselbe ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.