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.
Другие вопросы по тегам