Start-Process с PowerShell.exe демонстрирует другое поведение со встроенными одинарными и двойными кавычками.
Во-первых, на случай, если кто-то задается вопросом, почему мы вызываем PowerShell таким образом, я столкнулся с этим поведением с помощью более сложной команды, которую мы создавали, но это поведение можно продемонстрировать на более простом примере, как показано ниже. На практике мы запускаем команду в 32-разрядной оболочке PowerShell от имени администратора с дополнительными переменными, отображаемыми в строке (поэтому я просто не использую одинарные кавычки для внешней части), но, похоже, это не влияет на поведение ниже.
Когда я вызываю PowerShell через Start-Process
, Я получаю странное поведение, если использую одинарные кавычки, окружающие -Command
в исполняемый файл PowerShell. Например:
Start-Process -FilePath Powershell.exe -ArgumentList "-Command 'ping google.com'"
просто рендерит ping google.com
как выход и выходы. Однако, если я использую вложенные двойные кавычки вместо одинарных кавычек следующим образом:
Start-Process -FilePath Powershell.exe -ArgumentList "-Command `"ping google.com`""
ping
запускается и производит ожидаемый результат:
Проверка связи с google.com [173.194.78.113] с 32 байтами данных:
Ответ от 173.194.78.113: байты =32 время =34 мс TTL=45
Ответ от 173.194.78.113: байты =32 время = 33 мс TTL=45
Ответ от 173.194.78.113: байты =32 время =35 мс TTL=45
Ответ от 173.194.78.113: байты =32 время =32 мс TTL=45
Статистика пинга для 173.194.78.113:
Пакетов: отправлено = 4, принято = 4, потеряно = 0 (потеря 0%),
Приблизительное время в оба конца в миллисекундах:
Минимум =32 мс, максимум =35 мс, средний = 33 мс
Почему командная строка просто отображается как есть, а не выполняется, если я использую одинарные кавычки для -Command
параметр вместо двойных кавычек?
3 ответа
js2010 правильный ответ в том смысле, что использованиеStart-Process
связано с вашим вопросом и что поведение специфично для интерфейса командной строки PowerShell ( powershell.exe
для Windows PowerShell и pwsh
для PowerShell [Core] 6+):
В Windows[1], есть два слоя оценки рассмотреть следующие вопросы:
(а) Первоначальный разбор командной строки на аргументы.
(b) Оценка результирующих аргументов (объединенных пробелами) в виде кода PowerShell из-за использования
-Command
(-c
) Параметр CLI.
По поводу (а):
Как и большинство консольных программ в Windows, PowerShell распознает только "
символы. (двойные кавычки) - не тоже'
(одинарные кавычки) - как имеющие синтаксическую функцию.[2]
То есть, если
"
символы. которые убежали, они разделители строк, которые сами удаляются во время синтаксического анализа.Как следует из вышеизложенного,
'
символы. которые не удаляются.
Какие бы аргументы ни были результатом - массив возможных "
-stripped tokens - объединяются с одним пробелом между ними, который становится входом для (b).
Чтобы объяснить это в контексте вашего примера, с Start-Process
снято с картинки:
Примечание. Следующее относится к вызовам изcmd.exe
или любой контекст, в котором не задействована оболочка (включаяStart-Process
и WinKey-R диалоговое окно " Выполнить" Windows ()). Напротив, PowerShell повторно цитирует командную строку за кулисами, чтобы всегда использовать"
, если нужно.
Другими словами, следующее относится к командным строкам в том виде, в котором их видит PowerShell.
Команда в одинарных кавычках:
# Note: This *would* work for calling ping if run from
# (a) PowerShell itself or (b) from a POSIX-like shell such as Bash.
# However, via cmd.exe or any context where *no* shell is involved,
# notably Start-Process and the Windows Run dialog, it does not.
powershell -Command 'ping google.com'
(а) приводит к тому, что PowerShell находит следующие два дословных аргумента:
'ping
а такжеgoogle.com'
(б) объединяет эти дословные аргументы, чтобы сформировать
'ping google.com'
[2] и выполняет это как код PowerShell, поэтому выводит содержимое этого строкового литерала,ping google.com
Команда в двойных кавычках:
powershell -Command "ping google.com"
(а) приводит к тому, что PowerShell удаляет синтаксис
"
символов, найдя следующий единственный дословный аргумент:ping google.com
(б) затем приводит к этому дословному аргументу -
ping google.com
- выполняется как код PowerShell, что приводит к вызову команды, а именноping
исполняемый файл с аргументомgoogle.com
.
[1] На Unix-подобных платформах, первый слой не применяется, потому что программы должны быть вызвана только когда - либо увидеть массив из стенографических аргументов, а не из командной строки, что они сами должны разобрать в аргументы. Не то чтобы, если вы вызываете PowerShell CLI из POSIX-подобной оболочки, такой какbash
на Unix-подобных платформах именно оболочка распознает одинарные кавычки как разделители строк и удаляет их до того, как их увидит PowerShell.
[2] Удивительно, но на Windows, это в конечном счете, до каждой отдельной программы для интерпретации командной строки, а некоторые действительно решили также признать'
как разделители строк (например, Ruby). Однако многие программы в Windows, включая саму PowerShell, основаны на среде выполнения C, которая распознает только"
.
[3] Отметим, что это означает, что происходит нормализация пробелов: то есть
powershell -Command 'ping google.com'
в равной степени приведет к 'ping google.com'
.
Мы можем отбросить start-process отсюда. Кажется правдой, что встроенные двойные и одинарные кавычки по-разному обрабатываются исполняемым файлом powershell. Start-process не имеет отношения к этому поведению. Так PowerShell ведет себя в командной строке. Я не вижу способа это изменить. Вы также можете выполнить "start-job -runas32", но он не будет повышен. Другой вариант - это параметр PowerShell "-file" вместо "-command". Эти примеры запускаются из ядра Osx (unix) powershell:
pwsh -c "'ping -c 1 google.com'"
ping -c 1 google.com
pwsh -c "`"ping -c 1 google.com`""
PING google.com (172.217.10.110): 56 data bytes
64 bytes from 172.217.10.110: icmp_seq=0 ttl=52 time=20.020 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 20.020/20.020/20.020/0.000 ms
pwsh -c '"ping -c 1 google.com"'
PING google.com (172.217.6.206): 56 data bytes
64 bytes from 172.217.6.206: icmp_seq=0 ttl=52 time=22.786 ms
--- google.com ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 22.786/22.786/22.786/0.000 ms
В справке по powershell.exe ничего не упоминается о поддержке одинарных кавычек... зачем вам их использовать?
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
If the value of Command is "-", the command text is read from standard
input.
If the value of Command is a script block, the script block must be enclosed
in braces ({}). You can specify a script block only when running PowerShell.exe
in Windows PowerShell. The results of the script block are returned to the
parent shell as deserialized XML objects, not live objects.
If the value of Command is a string, Command must be the last parameter
in the command , because any characters typed after the command are
interpreted as the command arguments.
To write a string that runs a Windows PowerShell command, use the format:
"& {<command>}"
where the quotation marks indicate a string and the invoke operator (&)
causes the command to be executed.