¿Cómo envío texto sin una nueva línea en PowerShell?

145

Quiero que mi script de PowerShell imprima algo como esto:

Enabling feature XYZ......Done

El guión se parece a esto:

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

Pero Write-Outputsiempre imprime una nueva línea al final para que mi salida no esté en una línea. ¿Hay alguna forma de hacer esto?

Amit G
fuente
3
Posible duplicado de Evitar nueva línea en la salida de escritura
Michael Freidgeim

Respuestas:

165

Write-Host -NoNewline "Habilitando la función XYZ ......."

Shay Levy
fuente
62
Voto negativo porque el ejemplo del OP utiliza específicamente Write-Output, que tiene una función muy diferente a la de Write-Host. Los lectores deben tener en cuenta esta gran discrepancia antes de copiar / pegar la respuesta.
NathanAldenSr
55
Estoy de acuerdo con @NathanAldenSr, Write-Host no ayuda si usted está tratando de salida a un archivo, etc.
stevethethread
66
Write-HostCasi nunca es la respuesta correcta. Es el equivalente a hacerlo >/dev/ttyen Unixland.
Mark Reed
2
Write-Progresspuede ser apropiado en algunos casos, vea el ejemplo a continuación.
Thomas
12
Votado negativamente porque el ejemplo del OP se usa específicamente Write-Output. Write-Outputno tiene el -NoNewLineparámetro
Slogmeister Extraordinaire
49

Desafortunadamente, como se señaló en varias respuestas y comentarios, Write-Hostpuede ser peligroso y no puede canalizarse a otros procesos y Write-Outputno tiene el-NoNewline bandera.

Pero esos métodos son las formas "* nix" de mostrar la progresión, la forma "PowerShell" de hacerlo parece ser Write-Progress: muestra una barra en la parte superior de la ventana de PowerShell con información de progreso, disponible desde PowerShell 3.0 en adelante, consulte el manual para detalles.

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

Y para tomar el ejemplo del 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"
Thomas
fuente
3
Creo que esta es la mejor solución para mostrar el estado. Si necesita tener un registro o algo, tiene que vivir con el salto de línea de Write-Output.
fadanner
1
De acuerdo, además el punto de visualización progresiva es "ser elegante" para la instalación en vivo, no tiene sentido tenerlo en los archivos de registro: imprima "comenzar a hacer algo" y luego "hacer algo"
Thomas
13

Si bien es posible que no funcione en su caso (ya que está proporcionando resultados informativos al usuario), cree una cadena que pueda usar para agregar resultados. Cuando llegue el momento de enviarlo, simplemente envíe la cadena.

Ignorando, por supuesto, que este ejemplo es tonto en su caso pero útil en concepto:

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

Muestra:

Enabling feature XYZ.......Done
shufler
fuente
1
Esto puede funcionar en el ejemplo específico proporcionado, pero todavía hay un avance de línea adicional producido por Write-Output. Solución razonable, pero no una solución.
Slogmeister Extraordinaire
Write-Output siempre genera una nueva línea al final. No hay forma de evitar eso con este cmdlet
shufler
77
Este no es el punto, ya que la salida completa aparece después de instalar la función.
majkinetor
10
No entiendo, quién da más de 1 respuesta a esta pregunta, porque este no es el punto, ya que la salida completa aparece DESPUÉS de que se instala la función
maxkoryukov
1
"Ignorando, por supuesto, que este ejemplo es tonto en su caso pero útil en concepto:"
shufler
6

Sí, como otras respuestas tienen estados, no se puede hacer con Write-Output. Cuando PowerShell falla, recurra a .NET, incluso hay un par de respuestas .NET aquí, pero son más complejas de lo necesario.

Solo usa:

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

No es el PowerShell más puro, pero funciona.

Mark Travis
fuente
55
Votaron en contra porque esto se comporta igual Write-Host, excepto que la gente no lo esperará.
JBert
4

Para escribir en un archivo, puede usar una matriz de bytes. El siguiente ejemplo crea un archivo ZIP vacío, al que puede agregar archivos:

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

O usar:

[Byte[]] $text = [System.Text.Encoding]::UTF8.getBytes("Enabling feature XYZ.......")
[System.IO.File]::WriteAllBytes("C:\My.zip", $text)
FrinkTheBrave
fuente
¡Ese es un ejemplo increíble!
Peter Mortensen
2

Una simplificación a la respuesta de FrinkTheBrave:

[System.IO.File]::WriteAllText("c:\temp\myFile.txt", $myContent)
Russell Speight
fuente
Esto no responde a la pregunta en absoluto.
NathanAldenSr
2
Pero es exactamente lo que busqué y lo que esperaba del título de la pregunta.
Patrick Roocks
2

El problema que encontré fue que Write-Output en realidad interrumpe la salida cuando se usa PowerShell v2, al menos para stdout. Estaba tratando de escribir un texto XML para stdout sin éxito, porque sería difícil en el carácter 80.

La solución era usar

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

Esto no fue un problema en PowerShell v3. Write-Output parece estar funcionando correctamente allí.

Dependiendo de cómo se invoque el script de PowerShell, es posible que deba usar

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

antes de escribir a stdout.

esfuerzo
fuente
2
Se comporta como Write-Host, pero peor. No puede canalizarlo al archivo, por ejemplo.
majkinetor
2

Parece que no hay forma de hacer esto en PowerShell. Todas las respuestas anteriores no son correctas, porque no se comportan de la manera en que se Write-Outputcomportan, sino más bienWrite-Host no tienen este problema de todos modos.

La solución de cierre parece usarse Write-Hostcon el -NoNewLineparámetro. No puede canalizar esto, lo cual es un problema en general, pero hay una manera de anular esta función como se describe en Write-Host => Exportar a un archivo , por lo que puede hacer que acepte fácilmente el parámetro para un archivo de salida. Esto aún está lejos de ser una buena solución. Con Start-Transcriptesto es más útil, pero ese cmdlet tiene problemas con las aplicaciones nativas.

Write-Outputsimplemente no puede hacer lo que necesita en un contexto general.

majkinetor
fuente
2

Write-Hostes terrible, un destructor de mundos, sin embargo, puede usarlo solo para mostrar el progreso a un usuario mientras lo usa Write-Outputpara iniciar sesión (no es que el OP solicite el registro).

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"
}
eodeluga
fuente
Dependiendo de sus necesidades para indicar el progreso, también hay Write-Progress.
chwarr
1

Simplemente no puede hacer que PowerShell omita esas molestas líneas nuevas ... No hay ningún script o cmdlet que lo haga. Por supuesto, Write-Host es una tontería absoluta, ¡porque no puedes redirigirlo / canalizarlo!

Sin embargo, puede escribir su propio archivo EXE para hacerlo, que es lo que le expliqué cómo hacer en la pregunta de desbordamiento de pila Cómo generar algo en PowerShell .

samthebest
fuente
2
Información incorrecta. Como Shay y Jay respondieron excelentemente, simplemente agregue -NoNewline como primer argumento.
David en HotspotOffice
2
Tal vez ese sea el caso ahora en @DavidatHotspotOffice, pero cuando toqué por última vez un cuadro de Windows (hace más de un año) que no funcionaba, no podía redirigir / canalizar desde Write-Host. Para ser justos, no tenía la más mínima paciencia para POSH o .NET, lo dejé después de unos meses y volví a Unix Land. divertido
samthebest
3
@DavidatHotspotOffice - En realidad, tiene razón. No hay un argumento "NoNewLine" para Write-Output, que es sobre lo que estaba preguntando la pregunta original. Parece que hay algunas buenas razones para usar Write-Output, por lo que esta respuesta tiene sentido. jsnover.com/blog/2013/12/07/write-host-considered-harmful
James Ruskin
Vota abajo porque la pregunta es pedir una solución "en PowerShell". Escribir un EXE externo no es "En PowerShell".
Slogmeister Extraordinaire
1
@SlogmeisterExtraordinaire No es posible en PowerShell, por lo tanto, mi respuesta es razonable. Simplemente estás votando porque estás tan triste que tienes que trabajar con el peor sistema operativo del mundo que tiene el peor caparazón del mundo.
samthebest
1

La respuesta de shufler es correcta. Dicho de otra manera: en lugar de pasar los valores a Write-Output utilizando el FORMATO ARRAY,

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

o el equivalente por múltiples llamadas a Write-Output,

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

primero concatene sus componentes en una VARIABLE DE CADENA:

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

Esto evitará los CRLF intermedios causados ​​por llamar a Write-Output varias veces (o ARRAY FORM), pero, por supuesto, no suprimirá el CRLF final del comando de escritura de salida. Para eso, tendrá que escribir su propio comando, usar una de las otras soluciones enrevesadas enumeradas aquí o esperar hasta que Microsoft decida admitir el-NoNewline opción de Escritura-Salida.

Su deseo de proporcionar un medidor de progreso textual a la consola (es decir, "...") en lugar de escribir en un archivo de registro, también debe satisfacerse utilizando Write-Host. Puede lograr ambas cosas al recopilar el texto del mensaje en una variable para escribir en el registro Y usar Write-Host para proporcionar progreso a la consola. Esta funcionalidad se puede combinar en su propio comando para una mejor reutilización del código.

David Rudd
fuente
Prefiero esta respuesta sobre las otras. Si está llamando a propiedades de objetos, no puede encerrarlas entre comillas, así que utilicé: Write-Output ($ msg = $ MyObject.property + "Algún texto que quiero incluir" + $ Object.property)
Lewis
2
@Lewis ¡Sin duda puede incluir propiedades de objeto dentro de una cadena! Use la expresión $ () para rodear cualquier variable, por ejemplo, "$ ($ MyObject.Property) Algún texto que quiero incluir $ ($ Object.property)"
shufler
Esto puede funcionar en el ejemplo específico proporcionado, pero todavía hay un avance de línea adicional producido por Write-Output , simplemente no puede verlo porque es lo último escrito. Solución razonable, pero no una solución. Puede haber algo que consume la salida resultante que no puede manejar la nueva línea final.
Slogmeister Extraordinaire
1
Incorrecto. La solución no se puede hacer con un solo comando.
majkinetor
Esto no aborda la pregunta. La salida del archivo de registro debe mostrar la operación que estaba a punto de intentarse para que se pueda ver y rastrear la falla. La concatenación no logra eso.
durette
0

Lo siguiente colocará el cursor hacia atrás al comienzo de la fila anterior. Depende de usted colocarlo en la posición horizontal correcta (usando $ pos.X para moverlo hacia los lados):

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

Su salida actual es de 27 espacios, por lo que $ pos.X = 27 podría funcionar.

Will Martin
fuente
Esto no tiene nada que ver con la salida del archivo.
Slogmeister Extraordinaire
Tampoco es tan malo. Puede producir la salida correcta si usted $pos.Xtambién lo hace. El problema es que si lo canaliza a un archivo, aparecen dos líneas separadas.
majkinetor
0

Puede que no sea terriblemente elegante, pero hace exactamente lo que OP solicitó. Tenga en cuenta que el ISE se mete con StdOut, por lo que no habrá salida. Para que este script funcione, no se puede ejecutar dentro del 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()
Slogmeister Extraordinaire
fuente
1
Incorrecto. Si coloca eso en un archivo y canaliza su salida, no aparece nada.
majkinetor
La canalización a un archivo no fue algo que solicitó el OP. Y sí, [System.Console]no se puede redirigir a un archivo.
Slogmeister Extraordinaire
0

Hice trampa, pero creo que esta es la única respuesta que aborda todos los requisitos. Es decir, esto evita el CRLF final, proporciona un lugar para que se complete la otra operación mientras tanto, y redirige adecuadamente a stdout según sea necesario.

$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.'
dureta
fuente
0
$host.UI.Write('Enabling feature XYZ.......')
Enable-SPFeature...
$host.UI.WriteLine('Done')
BG100
fuente
0

o / p deseado: Habilitando la función XYZ ...... Listo

puedes usar el siguiente comando

$ a = "Habilitando la función XYZ"

Salida de escritura "$ a ...... Listo"

tienes que agregar variables y sentencias entre comillas. Espero que esto sea útil :)

Gracias Techiegal

techiegal
fuente
Write-Output se prefiere para colocar objetos en la tubería. Para la visualización de texto, Write-Host se usa con frecuencia y, más recientemente, Write-Information se usa para escribir en el flujo de información.
Logicaldiagram
0

Ya hay tanta respuesta aquí, nadie se desplazará hacia abajo aquí. De todos modos, también hay una solución para escribir texto sin una nueva línea al final, con lo siguiente:

Salida de archivo con codificación:

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

Salida de consola:

  # 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; }
SchLx
fuente
-3

Absolutamente puedes hacer esto. Write-Output tiene un indicador llamado " NoEnumerate " que es esencialmente lo mismo.

Olfativo
fuente