Как заставить ($Line_1`n$Line_2) работать в CMD-скрипте?
Я использую следующий код в файле сценария CMD
PowerShell Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show($Line_1)
Выше будет показано только
($Line_1)
Если
($Line_1`n$Line_2)
используется, ничего не будет показано.
Как мне показать оба
$Line_1
и
$Line_2
?
3 ответа
Очевидно
$Line_1 + "`n" + $Line_2
и
"$Line_1`n$Line_2"
работает нормально. Просто сложно отправить командную строку в PowerShell из cmd с его устаревшими причудами, потому что:
- В cmd
()
специальные символы, обозначающие блок - Разделитель токенов - это не только
<space>
и<tab>
но также <tcode id="46721"></tcode> <tcode id="46723"></tcode> <tcode id="46725"></tcode> <tcode id="46727"></tcode> и <tcode id="46729"></tcode>
PowerShell ожидает, что команда будет представлена в виде одной строки в последнем параметре, поэтому вам нужно заключить все в кавычки или избежать всех разделителей. Самое простое решение - использовать одну строку и избегать кавычек следующим образом
PowerShell "Add-Type -AssemblyName System.Windows.Forms; $Line_1 = 'Hello!'; $Line_2 = 'How are you?'; [System.Windows.Forms.MessageBox]::Show($Line_1 + \"`n\" + $Line_2)"
Если вы хотите поместить команды в несколько строк, вы не можете заключить строку в кавычки. Чтобы представить все это как один аргумент, теперь вам нужно экранировать все пробелы (вам почему-то не нужно экранировать
;
в этом случае, возможно потому, что после передачи командной строки в PowerShell он вызывает
GetCommandLineW
и снова разбирает все само)
PowerShell Add-Type^ -AssemblyName^ System.Windows.Forms;^
$Line_1^ =^ 'Hello!';^
$Line_2^ =^ 'How^ are^ you?';^
[Windows.Forms.MessageBox]::Show($Line_1^ +^ \"`n\"^ +^ $Line_2)"
В качестве альтернативы вы можете избежать этого
"`n"
строка, получив новую строку напрямую с помощью
[char]10
PowerShell -Command Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show($Line_1 + [char]10 + $Line_2)
Наконец, решение, которое работает без каких-либо побегов, которое использует
EncodedCommand
параметр PowerShell, который получает строку в кодировке base64 командной строки UTF-16. Вы можете получить закодированную версию, запустив ее в PowerShell.
$str = @'
>> Add-Type -AssemblyName System.Windows.Forms;
>> $Line_1 = 'Hello!';
>> $Line_2 = 'How are you?';
>> [System.Windows.Forms.MessageBox]::Show($Line_1 + "`n" + $Line_2)
>> '@
PS C:\Users\phucl> [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($str))
QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7AAoAIAA9ACAAJwBIAGUAbABsAG8AIQAnADsACgAgAD0AIAAnAEgAbwB3ACAAYQByAGUAIAB5AG8AdQA/ACcAOwAKAFsAUwB5AHMAdABlAG0ALgBXAGkAbgBkAG8AdwBzAC4ARgBvAHIAbQBzAC4ATQBlAHMAcwBhAGcAZQBCAG8AeABdADoAOgBTAGgAbwB3ACgAIAArACAAIgAKACIAIAArACAAKQA=
После наличия закодированной версии вы можете вызвать это из cmd
PowerShell -EncodedCommand QQBkAGQALQBUAHkAcABlACAALQBBAHMAcwBlAG0AYgBsAHkATgBhAG0AZQAgAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwA7AAoAJABMAGkAbgBlAF8AMQAgAD0AIAAnAEgAZQBsAGwAbwAhACcAOwAKACQATABpAG4AZQBfADIAIAA9ACAAJwBIAG8AdwAgAGEAcgBlACAAeQBvAHUAPwAnADsACgBbAFMAeQBzAHQAZQBtAC4AVwBpAG4AZABvAHcAcwAuAEYAbwByAG0AcwAuAE0AZQBzAHMAYQBnAGUAQgBvAHgAXQA6ADoAUwBoAG8AdwAoACQATABpAG4AZQBfADEAIAArACAAIgBgAG4AIgAgACsAIAAkAEwAaQBuAGUAXwAyACkA
Ответ phuclv содержит хорошую справочную информацию и жизнеспособные решения.
Самое простое решение:
PowerShell -c Add-Type -AssemblyName System.Windows.Forms;^
$Line_1 = 'Hello!';^
$Line_2 = 'How are you?';^
[System.Windows.Forms.MessageBox]::Show(\"$Line_1`nLine2\")
Обратите внимание, что я явно добавил имя параметра (), чтобы сигнализировать о том, что передается командная строка PowerShell. Хотя это не обязательно в Windows PowerShell , которая по умолчанию используется, она находится в PowerShell (Core) 7+, где теперь используется по умолчанию - см. Документацию CLI для Windows PowerShell и PowerShell (Core) 7+.
То есть вы должны использовать
$Line_1`n$Line_2
внутри - расширяемая строка , и вы должны
\
-экранировать символы, чтобы PowerShell не удалял их в ходе синтаксического анализа командной строки (при отсутствии общих двойных кавычек,
"""
тоже работает).
Предостережения :
Этот многострочный метод, который синтаксически не может использовать внешние кавычки для всей команды, требует тщательного экранирования всех метасимволов, которые должны быть переданы в PowerShell , особенно
>
, , и|
- если эти символы не входят в подстроку, заключенную в двойные кавычки; например,&
помещенный внутри\"...\"
строка - например\"$Line_1`n & $Line_2\"
- должен не быть убежал.- В виде исключения метасимвол
%
всегда нужно экранировать как%%
.
- В виде исключения метасимвол
Каждый оператор должен быть завершен (как вы это сделали), потому что продолжение строки (
^
) Приводит не новой строки между строк ввода, поэтому PowerShell видит их как одну линию , на которой должно быть несколько операторов;
-разделено.Потому что ни
cmd.exe
ни начальный синтаксический анализ командной строки PowerShell не знает о строках в одинарных кавычках ('...'
), такие строки разбиваются на несколько аргументов, если они содержат пробелы, что означает, что, по сути, выполнение нескольких смежных пробелов внутри таких строк нормализуется до одного пробела каждая. Например,'How are you?'
, в конечном итоге рассматривается как'How are you?'
от PowerShell; чтобы этого избежать, используйте двойные кавычки (с\"
-эскейп).
Как PowerShell анализирует аргументы, переданные его CLI
-Command
/
-c
параметр:
PowerShell дает вам выбор между передачей командной строки
либо: как один аргумент, заключенный в общее; например:
-
powershell -c "Get-Date -Format 'yyyy MMM'"
-
или: несколько аргументов - возможно, индивидуально
"..."
-quoted - к которому PowerShell затем присоединяется, чтобы сформировать единую строку; например:-
powershell -c Get-Date -Format "'yyyy MMM'"
-
В обоих случаях неэкранированные символы удаляются из аргументов, поскольку предполагается, что они имеют просто синтаксическую функцию ради командной строки, а не результирующей команды PowerShell.
После удаления синтаксиса
"
и объединяя полученные аргументы с пробелами, если применимо, Powershell интерпретирует полученную строку как код PowerShell .
Примечание: это принципиально отличается от того, как анализируются аргументы при использовании
-File
Параметр CLI для вызова файла сценария и передачи ему аргументов - подробнее см. В этом ответе .
Есть несколько способов объединения строк, которые вы можете найти, но, вероятно, самый простой способ - использовать символ +. `n - это символ новой строки, который помещает Строку 2 под строкой 1. Обратите внимание, что` - это символ обратной кавычки (обычно на той же клавише, что и тильда ~)
[System.Windows.Forms.MessageBox]::Show($Line_1 + "`n" + $Line_2)
Посмотрев еще раз на ваш пост, я заметил, что вы были близки с ($Line_1`n $Line_2). Вам не хватает только некоторых двойных кавычек
[System.Windows.Forms.MessageBox]::Show("$Line_1`n$Line_2")
Powershell с радостью заменяет переменные их значениями, помещенными в двойные кавычки. Вы можете узнать больше о расширяемых строках здесь и здесь