Jak wyprowadzić tekst bez nowej linii w programie PowerShell?

145

Chcę, aby mój skrypt PowerShell wydrukował coś takiego:

Enabling feature XYZ......Done

Skrypt wygląda mniej więcej tak:

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

Ale Write-Outputzawsze wypisuje nowy wiersz na końcu, więc mój wynik nie znajduje się w jednym wierszu. Czy jest na to sposób?

Amit G.
źródło
3
Możliwy duplikat unikania
znaku

Odpowiedzi:

165

Write-Host -NoNewline "Włączanie funkcji XYZ ......."

Shay Levy
źródło
62
Głosowanie negatywne, ponieważ przykład PO konkretnie używa Write-Output, który ma znacznie inną funkcję niż Write-Host. Czytelnicy powinni zwrócić uwagę na tę dużą rozbieżność przed skopiowaniem / wklejeniem odpowiedzi.
NathanAldenSr
5
Zgadzam się z @NathanAldenSr, Write-Host nie pomaga, jeśli próbujesz wyprowadzić do pliku itp.
stevethethread
6
Write-Hostprawie nigdy nie jest właściwą odpowiedzią. To odpowiednik pracy >/dev/ttyw Unixlandzie.
Mark Reed
2
Write-Progressmoże być odpowiednie w niektórych przypadkach, patrz przykład poniżej.
Thomas
12
Głosowanie negatywne, ponieważ przykład PO konkretnie używa Write-Output. Write-Outputnie ma -NoNewLineparametru.
Slogmeister Extraordinaire
49

Niestety, jak zauważono w kilku odpowiedziach i komentarzach, Write-Hostmoże być niebezpieczny i nie można go przesłać potokiem do innych procesów i Write-Outputnie ma -NoNewlineflagi.

Jednak metody te są „* nix” Sposoby progresji wyświetlacza, sposób „PowerShell” do zrobienia, że wydaje się być Write-Progress: wyświetla pasek w górnej części okna PowerShell z informacjami o postępach, dostępnego od PowerShell 3.0 dalszej, patrz instrukcja dla Detale.

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

I weźmy przykład 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"
Tomasz
źródło
3
Myślę, że to najlepsze rozwiązanie do pokazywania statusu. Jeśli potrzebujesz dziennika lub czegoś innego, musisz żyć z przełamaniem linii w trybie Write-Output.
fadanner
1
Zgoda, a celem wyświetlania progresywnego jest po prostu „mieć ochotę” podczas instalacji na żywo, nie ma sensu umieszczać tego w plikach dziennika: drukuj „zacznij coś robić”, a następnie „zrób coś”
Thomas
13

Chociaż może to nie działać w twoim przypadku (ponieważ dostarczasz użytkownikowi informacje wyjściowe), utwórz ciąg, którego możesz użyć do dołączenia wyniku. Kiedy nadejdzie czas, aby go wyprowadzić, po prostu wyślij ciąg.

Ignorując oczywiście, że ten przykład jest głupi w twoim przypadku, ale przydatny w koncepcji:

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

Wyświetlacze:

Enabling feature XYZ.......Done
shufler
źródło
1
Może to zadziałać w konkretnym podanym przykładzie, ale nadal istnieje dodatkowy wysuw wiersza utworzony przez Write-Output. Rozsądne obejście, ale nie rozwiązanie.
Slogmeister Extraordinaire
Write-Output zawsze wyświetla na końcu znak nowej linii. Nie
da się
7
Nie o to chodzi, ponieważ całe dane wyjściowe pojawiają się po zainstalowaniu funkcji.
majkinetor
10
Nie rozumiem, kto daje więcej niż 1 upwote na to pytanie, ponieważ nie
maxkoryukov
1
„Ignorując oczywiście, że ten przykład jest głupi w twoim przypadku, ale przydatny w koncepcji:”
shufler,
6

Tak, ponieważ inne odpowiedzi mają stany, nie można tego zrobić za pomocą Write-Output. Tam, gdzie PowerShell nie działa, zwróć się do .NET, jest tu nawet kilka odpowiedzi dotyczących .NET, ale są one bardziej złożone niż powinny.

Po prostu użyj:

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

Nie jest to najczystszy PowerShell, ale działa.

Mark Travis
źródło
5
Negocjowany, ponieważ zachowuje się tak samo Write-Host, ale ludzie się tego nie spodziewają.
JBert
4

Aby zapisać do pliku, możesz użyć tablicy bajtów. Poniższy przykład tworzy pusty plik ZIP, do którego można dodawać pliki:

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

Albo użyj:

[Byte[]] $text = [System.Text.Encoding]::UTF8.getBytes("Enabling feature XYZ.......")
[System.IO.File]::WriteAllBytes("C:\My.zip", $text)
FrinkTheBrave
źródło
To wspaniały przykład!
Peter Mortensen
2

Uproszczenie odpowiedzi FrinkTheBrave:

[System.IO.File]::WriteAllText("c:\temp\myFile.txt", $myContent)
Russell Speight
źródło
To wcale nie odpowiada na pytanie.
NathanAldenSr
2
Ale właśnie tego szukałem i tego się spodziewałem po tytule pytania.
Patrick Roocks
2

Problem, który napotkałem, polegał na tym, że Write-Output faktycznie przerywa linię wyjściową podczas korzystania z PowerShell v2, przynajmniej na stdout. Próbowałem napisać tekst XML na standardowe wyjście bez powodzenia, ponieważ byłby mocno zawinięty w znak 80.

Obejście polegało na użyciu

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

To nie był problem w PowerShell v3. Wydaje się, że funkcja Write-Output działa tam poprawnie.

W zależności od sposobu wywoływania skryptu programu PowerShell może być konieczne użycie

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

zanim napiszesz na standardowe wyjście.

eythort
źródło
2
Zachowuje się jak Write-Host, ale gorzej. Nie możesz na przykład przesłać go do pliku.
majkinetor
2

Wydaje się, że nie ma sposobu, aby to zrobić w programie PowerShell. Wszystkie poprzednie odpowiedzi są niepoprawne, ponieważ nie zachowują się tak, jak się Write-Outputzachowują, a raczej takie, Write-Hostktóre i tak nie mają tego problemu.

Rozwiązanie close wydaje się używać Write-Hostz -NoNewLineparametrem. Nie można tego potokować, co jest ogólnie problemem, ale istnieje sposób na nadpisanie tej funkcji, jak opisano w Write-Host => Export do pliku , dzięki czemu można łatwo sprawić, by zaakceptował parametr dla pliku wyjściowego. To wciąż nie jest dobre rozwiązanie. Dzięki Start-Transcripttemu jest bardziej użyteczny, ale to polecenie cmdlet ma problemy z aplikacjami natywnymi.

Write-Outputpo prostu nie możesz zrobić tego, czego potrzebujesz w ogólnym kontekście.

majkinetor
źródło
2

Write-Hostjest okropny, niszczyciel światów, ale możesz go używać tylko do wyświetlania postępu użytkownikowi podczas korzystania Write-Outputz logowania (nie to, że OP prosił o logowanie).

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
źródło
W zależności od twoich potrzeb w zakresie wskazywania postępów, jest też Write-Progress.
chwarr
1

Po prostu nie można zmusić PowerShell do pominięcia tych nieznośnych znaków nowej linii ... Nie ma takiego skryptu ani polecenia cmdlet. Oczywiście, Write-Host to absolutny nonsens, ponieważ nie można z niego przekierować / potokować!

Niemniej jednak możesz napisać własny plik EXE, aby to zrobić, co wyjaśniłem w pytaniu o przepełnienie stosu Jak wyprowadzić coś w PowerShell .

samthebest
źródło
2
Błędne informacje. Jak świetnie odpowiedzieli Shay i Jay, po prostu dodaj -NoNewline jako pierwszy argument.
David w HotspotOffice
2
Może tak jest teraz @DavidatHotspotOffice, ale kiedy ostatnio dotknąłem okna systemu Windows (ponad rok temu), które nie działało, nie można było przekierować / potok z Write-Host. Szczerze mówiąc, nie miałem najmniejszej cierpliwości do POSH czy .NET, zrezygnowałem po kilku miesiącach i wróciłem do unixa. śmieszne
samthebest
3
@DavidatHotspotOffice - Właściwie ma rację. Nie ma argumentu „NoNewLine” dla Write-Output, o co pytano w pierwotnym pytaniu. Wydaje się, że istnieje kilka dobrych powodów, dla których warto używać funkcji Write-Output - więc ta odpowiedź ma sens. jsnover.com/blog/2013/12/07/write-host-considered-harmful
James Ruskin
Ocena negatywna, ponieważ pytanie dotyczy rozwiązania „w PowerShell”. Pisanie zewnętrznego pliku EXE nie odbywa się w programie PowerShell.
Slogmeister Extraordinaire
1
@SlogmeisterExtraordinaire W PowerShell nie jest to możliwe, dlatego moja odpowiedź jest rozsądna. Po prostu odrzucasz głos, ponieważ jesteś tak smutny, że musisz pracować z najgorszym systemem operacyjnym na świecie, który ma najgorszą powłokę na świecie.
samthebest
1

Odpowiedź Shuflera jest poprawna. Podane w inny sposób: Zamiast przekazywać wartości do Write-Output za pomocą ARRAY FORM,

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

lub ekwiwalent przez wielokrotne wywołania Write-Output,

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

najpierw połącz swoje komponenty w STRING VARIABLE:

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

Zapobiegnie to powstawaniu pośrednich list CRLF spowodowanych wielokrotnym wywołaniem Write-Output (lub ARRAY FORM), ale oczywiście nie pominie końcowego CRLF polecenia Write-Output. W tym celu będziesz musiał napisać własne polecenie, użyć jednego z innych zawiłych obejść wymienionych tutaj lub poczekać, aż Microsoft zdecyduje się obsługiwać -NoNewlineopcję zapisu-wyjścia.

Twoje pragnienie dostarczenia tekstowego miernika postępu do konsoli (tj. „…”) W przeciwieństwie do zapisywania do pliku dziennika, powinno być również zaspokojone przez użycie Write-Host. Możesz osiągnąć jedno i drugie, zbierając tekst msg do zmiennej w celu zapisania w dzienniku ORAZ używając Write-Host, aby zapewnić postęp konsoli. Funkcjonalność tę można połączyć we własne polecenie w celu maksymalnego ponownego wykorzystania kodu.

David Rudd
źródło
Wolę tę odpowiedź od innych. Jeśli wywołujesz właściwości obiektów, nie możesz ich ująć w cudzysłowy, więc użyłem: Write-Output ($ msg = $ MyObject.property + "Jakiś tekst, który chcę zawrzeć" + $ Object.property)
Lewis
2
@Lewis Z pewnością możesz zawrzeć właściwości obiektu wewnątrz ciągu! Użyj wyrażenia $ (), aby otoczyć dowolną zmienną, np. „$ ($ MyObject.Property) Jakiś tekst, który chcę uwzględnić $ ($ Object.property)”
shufler
Może to zadziałać w konkretnym podanym przykładzie, ale nadal istnieje dodatkowy wysuw wiersza Write-Output, po prostu nie możesz go zobaczyć, ponieważ jest to ostatnia rzecz zapisana. Rozsądne obejście, ale nie rozwiązanie. Może istnieć coś pochłaniającego wynikowe dane wyjściowe, co nie może obsłużyć końcowego znaku nowej linii.
Slogmeister Extraordinaire
1
Niepoprawne. Rozwiązania nie da się zrobić jednym poleceniem.
majkinetor
To nie odpowiada na pytanie. Dane wyjściowe pliku dziennika powinny pokazywać operację, która miała zostać podjęta, aby można było zobaczyć i prześledzić niepowodzenie. Konkatenacja tego nie osiąga.
durette
0

Poniższe instrukcje umieszczą kursor z powrotem na początku poprzedniego wiersza. Do Ciebie należy ustawienie go w odpowiedniej poziomej pozycji (używając $ pos.X, aby przesunąć go na boki):

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

Twoje aktualne wyjście ma 27 spacji, więc $ pos.X = 27 może działać.

Will Martin
źródło
Nie ma to nic wspólnego z plikiem wyjściowym.
Slogmeister Extraordinaire
Nie jest też tak źle. Jeśli $pos.Xrównież to zrobisz, może dać prawidłowe wyniki . Problem polega na tym, że jeśli przepuścisz go do pliku, pojawią się dwie oddzielne linie.
majkinetor
0

Może nie jest strasznie elegancki, ale robi dokładnie to, o co prosił OP. Zauważ, że ISE miesza się ze StdOut, więc nie będzie wyjścia. Aby zobaczyć, jak działa ten skrypt, nie można go uruchomić w 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
źródło
1
Niepoprawne. Jeśli umieścisz to w pliku i potokujesz wyjście, nic się nie pojawi.
majkinetor
Pipowanie do pliku nie było czymś, o co prosił OP. I tak, [System.Console]nie można przekierować do pliku.
Slogmeister Extraordinaire
0

Oszukiwałem, ale uważam, że to jedyna odpowiedź, która spełnia wszystkie wymagania. Mianowicie, pozwala to uniknąć końcowego CRLF, zapewnia miejsce na zakończenie innej operacji w międzyczasie i odpowiednio przekierowuje na standardowe wyjście, jeśli jest to konieczne.

$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
źródło
0
$host.UI.Write('Enabling feature XYZ.......')
Enable-SPFeature...
$host.UI.WriteLine('Done')
BG100
źródło
0

żądane o / p: Włączanie funkcji XYZ ...... Gotowe

możesz użyć poniższego polecenia

$ a = "Włączanie funkcji XYZ"

Wyjście do zapisu "$ a ...... Gotowe"

musisz dodać zmienną i instrukcję w cudzysłowie. mam nadzieję, że to jest pomocne :)

Dzięki Techiegal

techiegal
źródło
Funkcja Write-Output jest preferowana do umieszczania obiektów w potoku. W przypadku wyświetlania tekstu często używany jest Write-Host, a ostatnio Write-Information służy do zapisywania w strumieniu informacji.
logicaldiagram
0

Jest tu już tyle odpowiedzi, że nikt tutaj nie przewinie. W każdym razie istnieje również rozwiązanie umożliwiające pisanie tekstu bez nowej linii na końcu, z następującymi elementami:

Plik wyjściowy z kodowaniem:

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

Wyjście Consol:

  # 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
źródło
-3

Możesz to zrobić absolutnie. Write-Output ma flagę o nazwie „ NoEnumerate ”, która jest zasadniczo tym samym.

Smelltastic
źródło