Come posso generare testo senza una nuova riga in PowerShell?


145

Voglio che il mio script PowerShell stampi qualcosa del genere:

Enabling feature XYZ......Done

La sceneggiatura ha un aspetto simile al seguente:

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

Ma Write-Outputstampa sempre una nuova riga alla fine in modo che il mio output non sia su una riga. C'è un modo per fare questo?


Risposte:


165

Write-Host -NoNewline "Abilitazione della funzione XYZ ......."


62
Sottovalutato perché l'esempio dell'OP utilizza specificamente Write-Output, che ha una funzione molto diversa rispetto a Write-Host. I lettori dovrebbero notare questa grande discrepanza prima di copiare / incollare la risposta.
NathanAldenSr

5
Sono d'accordo con @NathanAldenSr, Write-Host non aiuta se stai cercando di eseguire l'output su un file, ecc.
stevethethread,

6
Write-Hostnon è quasi mai la risposta giusta. È l'equivalente di fare >/dev/ttyin Unixland.
Mark Reed,

2
Write-Progresspuò essere appropriato in alcuni casi, vedere l'esempio seguente.
Thomas,

12
Sottovalutato perché l'esempio dell'OP utilizza specificamente Write-Output. Write-Outputnon ha il -NoNewLineparametro
Slogmeister Extraordinaire,

49

Sfortunatamente, come indicato in diverse risposte e commenti, Write-Hostpuò essere pericoloso e non può essere convogliato ad altri processi e Write-Outputnon ha la -NoNewlinebandiera.

Ma questi metodi sono i modi "* nix" per visualizzare la progressione, il modo "PowerShell" per farlo sembra essere Write-Progress: mostra una barra nella parte superiore della finestra di PowerShell con informazioni sull'avanzamento, disponibile da PowerShell 3.0 in poi, vedere il manuale per dettagli.

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

E per fare l'esempio del PO:

# 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
Penso che questa sia la migliore soluzione per mostrare lo stato. Se hai bisogno di avere un registro o qualcosa del genere devi vivere con l'interruzione di linea di Write-Output.
fadanner,

1
D'accordo, oltre al punto di visualizzazione progressiva è solo "essere fantasiosi" per l'installazione dal vivo, non ha senso averlo nei file di registro: stampare "inizia a fare qualcosa" quindi "fatto facendo qualcosa"
Thomas

13

Anche se potrebbe non funzionare nel tuo caso (poiché stai fornendo un output informativo all'utente), crea una stringa che puoi usare per aggiungere l'output. Quando è il momento di emetterlo, basta emettere la stringa.

Ignorando ovviamente che questo esempio è sciocco nel tuo caso ma utile nel concetto:

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

Displays:

Enabling feature XYZ.......Done

1
Questo potrebbe funzionare nell'esempio specifico fornito, ma esiste ancora un feed di riga aggiuntivo prodotto da Write-Output. Soluzione ragionevole, ma non una soluzione.
Slogmeister Extraordinaire,

Write-Output genera sempre una nuova riga alla fine. Non c'è modo di aggirare questo con questo cmdlet
shufler,

7
Questo non è il punto poiché l'intero output appare dopo l'installazione della funzione.
Majkinetor,

10
Non capisco, chi dà più di 1 voto a questa domanda, perché questo non è il punto poiché l' intero output appare DOPO che la funzione è installata
maxkoryukov

1
"Ignorando ovviamente che questo esempio è sciocco nel tuo caso ma utile nel concetto:"
shufler

6

Sì, poiché altre risposte hanno degli stati, non può essere fatto con Write-Output. Laddove PowerShell fallisce, passa a .NET, ci sono anche un paio di risposte .NET qui, ma sono più complesse di quanto debbano essere.

Usa solo:

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

Non è PowerShell più puro, ma funziona.


5
Sottovalutato perché si comporta proprio così Write-Host, tranne che le persone non se lo aspettano.
JBert,

4

Per scrivere su un file è possibile utilizzare un array di byte. L'esempio seguente crea un file ZIP vuoto, al quale è possibile aggiungere file:

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

Oppure usa:

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

Questo è un esempio fantastico!
Peter Mortensen,

2

Una semplificazione alla risposta di FrinkTheBrave:

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

Questo non risponde affatto alla domanda.
NathanAldenSr

2
Ma è esattamente quello che ho cercato e quello che mi aspettavo dal titolo della domanda.
Patrick Roocks,

2

Il problema che ho riscontrato è stato che Write-Output interrompe effettivamente l'output quando si utilizza PowerShell v2, almeno per stdout. Stavo cercando di scrivere un testo XML su stdout senza successo, perché sarebbe stato complicato dal carattere 80.

La soluzione era di usare

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

Questo non era un problema in PowerShell v3. Scrivi-Output sembra funzionare correttamente lì.

A seconda di come viene invocato lo script PowerShell, potrebbe essere necessario utilizzarlo

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

prima di scrivere su stdout.


2
Si comporta come Write-Host, ma peggio. Ad esempio, non è possibile reindirizzarlo su file.
Majkinetor,

2

Sembra che non ci sia modo di farlo in PowerShell. Tutte le risposte precedenti non sono corrette, perché non si comportano come Write-Outputsi comporta ma più come Write-Hostse non avessero comunque questo problema.

La soluzione di chiusura sembra utilizzare Write-Hostcon il -NoNewLineparametro Non è possibile reindirizzare questo problema in genere, ma esiste un modo per sovrascrivere questa funzione come descritto in Write-Host => Esporta in un file , quindi è possibile farlo accettare facilmente il parametro per un file di output. Questo è ancora lontano dall'essere una buona soluzione. Con Start-Transcriptquesto è più utilizzabile, ma quel cmdlet ha problemi con le applicazioni native.

Write-Outputsemplicemente non puoi fare ciò di cui hai bisogno in un contesto generale.


2

Write-Hostè terribile, un distruttore di mondi, ma puoi usarlo solo per mostrare i progressi a un utente mentre utilizzi il Write-Outputlog (non che l'OP abbia richiesto il log).

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

A seconda delle tue esigenze per indicare i progressi, c'è anche Write-Progress.
Chwarr,

1

Semplicemente non puoi convincere PowerShell a omettere quelle fastidiose newline ... Non c'è script o cmdlet che lo faccia. Naturalmente, Write-Host è un'assurdità assoluta, perché non puoi reindirizzare / pipe da esso!

Tuttavia, puoi scrivere il tuo file EXE per farlo, che è quello che ho spiegato come fare nella domanda Stack Overflow Come eseguire l'output di qualcosa in PowerShell .


2
Informazioni errate Mentre Shay e Jay rispondevano in modo eccellente, è sufficiente aggiungere -NoNewline come primo argomento.
David all'HotspotOffice il

2
Forse è il caso ora @DavidatHotspotOffice ma quando ho toccato l'ultima volta una finestra di Windows (più di un anno fa) che non ha funzionato, non è stato possibile reindirizzare / pipe da Write-Host. Per essere onesti non ho avuto il minimo di pazienza per POSH o .NET, ho lasciato dopo alcuni mesi e sono tornato a unix land. divertente
Samthebest il

3
@DavidatHotspotOffice - In realtà, ha ragione. Non esiste alcun argomento "NoNewLine" per Write-Output, che è la domanda originale. Ci sono alcune buone ragioni, a quanto pare, per l'utilizzo di Write-Output - quindi questa risposta ha senso. jsnover.com/blog/2013/12/07/write-host-considered-harmful
James Ruskin

Sottovalutato perché la domanda richiede una soluzione "in PowerShell". La scrittura di un file EXE esterno non è "In PowerShell".
Slogmeister Extraordinaire,

1
@SlogmeisterExtraordinaire Non è possibile in PowerShell quindi la mia risposta è ragionevole. Stai solo effettuando il downvoting perché sei così triste che devi lavorare con il peggior sistema operativo del mondo che ha la shell peggiore del mondo.
Samthebest,

1

La risposta di shufler è corretta. Detto in altro modo: invece di passare i valori a Write-Output utilizzando il FORM ARRAY,

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

o l'equivalente di più chiamate a Write-Output,

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

concatena i tuoi componenti in un STRING VARIABLE prima:

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

Ciò impedirà i CRLF intermedi causati dalla chiamata di Output-Output più volte (o FORM ARRAY), ma ovviamente non sopprimerà il CRLF finale del comando di scrittura-output. Per questo, dovrai scrivere il tuo commandlet, utilizzare uno degli altri aggiramenti aggirati elencati qui o attendere che Microsoft decida di supportare l' -NoNewlineopzione per Write-Output.

Il tuo desiderio di fornire un indicatore di progresso testuale alla console (ad esempio "....") invece di scrivere in un file di registro, dovrebbe essere soddisfatto utilizzando Write-Host. È possibile eseguire entrambe le operazioni raccogliendo il testo di msg in una variabile per la scrittura nel registro E utilizzando Write-Host per fornire progressi alla console. Questa funzionalità può essere combinata nel proprio comando per il massimo riutilizzo del codice.


Preferisco di gran lunga questa risposta rispetto alle altre. Se stai chiamando le proprietà degli oggetti, non puoi racchiuderle tra virgolette, quindi ho usato: Write-Output ($ msg = $ MyObject.property + "Alcuni testi che voglio includere" + $ Object.property)
Lewis

2
@Lewis Puoi sicuramente includere le proprietà degli oggetti all'interno di una stringa! Usa l'espressione $ () per racchiudere qualsiasi variabile, ad esempio "$ ($ MyObject.Property) Alcuni testi che voglio includere $ ($ Object.property)"
shufler

Questo potrebbe funzionare nell'esempio specifico fornito, ma c'è ancora un feed di riga aggiuntivo prodotto da Write-Output, non puoi vederlo perché è l'ultima cosa scritta. Soluzione ragionevole, ma non una soluzione. Potrebbe esserci qualcosa che consuma l'output risultante che non è in grado di gestire la nuova riga finale.
Slogmeister Extraordinaire,

1
Non corretto. La soluzione non può essere eseguita con un singolo comando.
majkinetor

Questo non affronta la domanda. L'output del file di registro dovrebbe mostrare l'operazione che stava per essere tentata in modo da poter vedere e tracciare l'errore. La concatenazione non ci riesce.
Durette,

0

Quanto segue riposizionerà il cursore all'inizio della riga precedente. Sta a te posizionarlo nella giusta posizione orizzontale (usando $ pos.X per spostarlo lateralmente):

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

L'output corrente è di 27 spazi, quindi $ pos.X = 27 potrebbe funzionare.


Questo non ha nulla a che fare con l'output del file.
Slogmeister Extraordinaire,

Inoltre non è poi così male. Può produrre l'output corretto anche se lo fai $pos.X. Il problema è che se lo installi in un file, vengono visualizzate due linee separate.
majkinetor

0

Potrebbe non essere terribilmente elegante, ma fa esattamente ciò che OP ha richiesto. Si noti che ISE fa casini con StdOut, quindi non ci sarà output. Per vedere questo script funzionare non può essere eseguito all'interno di 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
Non corretto. Se lo metti in un file e pipe il suo output non appare nulla.
Majkinetor,

Il piping su un file non era qualcosa richiesto dall'OP. E sì, [System.Console]non può essere reindirizzato a un file.
Slogmeister Extraordinaire,

0

Ho tradito, ma credo che questa sia l'unica risposta che soddisfi ogni esigenza. Vale a dire, questo evita il CRLF finale, fornisce un posto per il completamento dell'altra operazione nel frattempo e reindirizza correttamente allo stdout, se necessario.

$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 desiderato: abilitazione della funzione XYZ ...... Fine

puoi usare il comando qui sotto

$ a = "Abilitazione della funzione XYZ"

Scrittura-output "$ a ...... Fatto"

devi aggiungere una variabile e un'istruzione tra virgolette. spero che sia utile :)

Grazie Techiegal


L'output di scrittura è preferito per mettere oggetti nella pipeline. Per la visualizzazione del testo, Write-Host viene spesso utilizzato e, più recentemente, Write-Information viene utilizzato per scrivere nel flusso di informazioni.
diagramma logico

0

C'è già così tanta risposta qui, nessuno scorrerà qui. Comunque c'è anche una soluzione per scrivere del testo senza una nuova riga alla fine, con il seguente:

Uscita file con codifica:

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

Consol output:

  # 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

Puoi assolutamente farlo. Write-Output ha un flag chiamato " NoEnumerate " che è essenzialmente la stessa cosa.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.