Як вивести текст без нового рядка в PowerShell?


145

Я хочу, щоб мій сценарій PowerShell надрукував щось подібне:

Enabling feature XYZ......Done

Сценарій виглядає приблизно так:

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

Але Write-Outputзавжди друкується новий рядок в кінці, щоб мій вихід був не на одному рядку. Чи є спосіб це зробити?


3

Відповіді:


165

Write-Host -NoNewline "Увімкнення функції XYZ ......."


62
Зрозуміло, тому що конкретно використовується приклад ОП Write-Output, який має значно інші функції, ніж Write-Host. Читачі повинні відзначити цю велику невідповідність перед копіюванням / вставкою відповіді.
NathanAldenSr

5
Я погоджуюся з @NathanAldenSr, Write-Host не допомагає, якщо ви намагаєтеся вивести файл тощо.
stevethethread

6
Write-Hostмайже ніколи не є правильною відповіддю. Це еквівалент діяльності >/dev/ttyв Unixland.
Марк Рід

2
Write-Progressможе бути доцільним у деяких випадках, див. приклад нижче.
Томас

12
Захищений тому, що конкретно використовується приклад ОП Write-Output. Write-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"

І взяти приклад ОП:

# 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
Погоджено, плюс точка прогресивного відображення - це просто "бути фантазією" для прямої установки, немає сенсу мати це у файлах журналів: надрукувати "почати щось робити", а потім "зроби щось робити"
Томас

13

Хоча це може не працювати у вашому випадку (оскільки ви надаєте інформаційний вихід користувачеві), створіть рядок, який ви можете використовувати для додавання виводу. Коли прийшов час вивести його, просто виведіть рядок.

Ігноруючи звичайно, що цей приклад у вашому випадку нерозумний, але корисний у концепції:

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

Відображає:

Enabling feature XYZ.......Done

1
Це може працювати в конкретному прикладі, але надається додаткова лінія каналів, що виробляється Write-Output. Розумне рішення, але не рішення.
Slogmeister Extraordinaire

Виведення-запис завжди виводить новий рядок в кінці. З цим командлетом не
обійтися

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)

Це приголомшливий приклад!
Пітер Мортенсен


2

Проблема, з якою я потрапила, полягала в тому, що Write-Output насправді лінійно розбиває вихід при використанні PowerShell v2, принаймні для stdout. Я намагався без успіху написати XML-текст у stdout, тому що це було б важко завершено символом 80.

Допомогти було вирішити

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

Це не було проблемою в PowerShell v3. Здається, запис-вихід там нормально працює.

Залежно від того, як викликається скрипт PowerShell, можливо, вам доведеться використовувати

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

перед тим, як написати в stdout.


2
Поводиться як Write-Host, але найгірше. Наприклад, ви не можете передавати його у файл.
майкінетор

2

Здається, у PowerShell цього немає способу зробити. Усі попередні відповіді невірні, тому що вони ведуть себе не так, як вони поводяться, Write-Outputа більше схожі на те, Write-Hostщо у цій проблемі все одно не виникає.

Рішення закриття, здається, використовується Write-Hostз -NoNewLineпараметром. Ви не можете передавати це, що є проблемою загалом, але є спосіб змінити цю функцію, як описано в Write-Host => Експорт у файл , тому ви можете змусити його прийняти параметр для вихідного файлу. Це ще далеко не вдале рішення. При Start-Transcriptцьому більш зручні, але командлет має проблеми з рідними додатками.

Write-Outputпросто не може робити те, що потрібно в загальному контексті.


2

Write-Hostце жахливо, руйнівець світів, але ви можете використовувати його просто для відображення прогресу користувачеві, використовуючи Write-Outputдля входу в журнал (не те, що ОП просило вести реєстрацію).

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.
чвар

1

Ви просто не можете змусити PowerShell опустити ці примхливі рядки ... Немає сценарію чи командлета, який би це не зробив. Звичайно, Write-Host - це абсолютно нісенітниця, тому що ви не можете перенаправити / передати з неї!

Тим не менш, ви можете написати свій власний файл EXE, щоб це зробити, це те, що я пояснив, як це зробити в питанні переповнення стека. Як вивести щось у PowerShell .


2
Неправильна інформація. Як відмінно відповіли Шай та Джей, просто додайте -NoNewline як перший аргумент.
Девід у HotspotOffice

2
Можливо, це так і зараз @DavidatHotspotOffice, але коли я востаннє торкнувся віконного вікна (більше року тому), який не працював, ви не змогли перенаправити / передати програму Write-Host. Щоб бути справедливим, у мене не було ні найменшого терпіння до POSH або .NET, я відмовився через кілька місяців і повернувся до Unix. смішно
samthebest

3
@DavidatHotspotOffice - Насправді він правильний. Немає аргументу "NoNewLine" для Write-Output, саме про це задавали оригінальне запитання. Здається, є кілька вагомих причин для використання Write-Output - тому ця відповідь має сенс. jsnover.com/blog/2013/12/07/write-host-considered-harmful
Джеймс

Неприхильне тому, що питання задає рішення "в PowerShell". Написання зовнішнього EXE не є "в PowerShell".
Slogmeister Extraordinaire

1
@SlogmeisterExtraordinaire У PowerShell це неможливо, тому моя відповідь розумна. Ваша справедливість, тому що ваша так сумна, що вам доведеться працювати з найгіршою в світі операційною системою, яка має гіршу оболонку у світі.
самтебест

1

Відповідь шуфлера правильна. Заявив інший спосіб: Замість передачі значень в Write-Output за допомогою ФОРМИ ARRAY,

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

або еквівалент багаторазових дзвінків на запис-вихід,

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

Це запобіжить проміжні CRLF, викликані багаторазовим викликом Write-Output (або ARRAY FORM), але, звичайно, не пригнічуватиме остаточний CRLF командної команди Write-Output. Для цього вам доведеться написати власну командну команду, скористатись одним із інших перелічених тут шляхів вирішення чи почекати, поки Microsoft вирішить підтримати-NoNewline опцію для запису-виводу.

Ваше бажання надати текстовий метр прогресу до консолі (тобто "...."), на відміну від запису до файлу журналу, також має бути задоволено за допомогою Write-Host. Ви можете досягти обох, зібравши текст msg у змінну для запису до журналу ТА за допомогою Write-Host, щоб забезпечити прогрес у консолі. Ця функціональність може бути об'єднана у власну командну команду для найбільшого використання коду.


Я дуже віддаю перевагу цій відповіді над іншими. Якщо ви називаєте властивості об'єктів, ви не можете їх укладати в лапки, тому я використав: Write-Output ($ msg = $ MyObject.property + "Деякий текст, який я хочу включити" + $ Object.property)
Lewis

2
@Lewis Ви, звичайно, можете включати властивості об'єкта всередині рядка! Використовуйте вираз $ () для оточення будь-якої змінної, наприклад "$ ($ MyObject.Property) Якийсь текст, який я хочу включити $ ($ Object.property)"
shufler

Це може працювати в конкретному прикладі, але поданий додатковий рядок подається Write-Output, ви просто не можете його побачити, оскільки це останнє написане. Розумне рішення, але не рішення. Можливо, щось, що споживає отриманий результат, не може обробити нижчий новий рядок.
Slogmeister Extraordinaire

1
Неправильно. Розв’язання не може бути виконано однією командою.
майкінетор

Це не стосується питання. Вихід з файлу журналу повинен показувати операцію, яку збирався здійснити, щоб помилку можна було побачити та простежити. Зв'язування цього не досягає.
дуретте

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також зробите це . Проблема полягає в тому, що якщо ви передаєте його у файл, з’являться два окремі рядки.
майкінетор

0

Це може бути не надзвичайно елегантно, але він робить саме те, що вимагала ОП. Зауважте, що 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
Неправильно. Якщо ви помістите це у файл та трубу, його вихід не з’явиться.
майкінетор

Передача файлу - це не те, чого вимагала ОП. І так, [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 ...... Готово"

Ви повинні додати змінну та заяву всередині лапок. сподіваюся, що це корисно :)

Дякую Текіегал


Виписування вигідніше для виведення об'єктів на трубопровід. Для відображення тексту часто використовується "Write-Host", а останнім часом Write-Information використовується для запису в потік інформації.
logicdiagram

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 ", що є по суті тим самим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.