Захват результатов команды PowerShell в цикле командного файла для / f - PullRequest
0 голосов
/ 29 апреля 2018

Этот код PowerShell выбирает правильное значение для var5 из этой строки. Желаемый результат это «Alert Raised».

PS C:\src\t> $s = 'Status 58   var5=Alert Raised on: March'
PS C:\src\t> $s
Status 58   var5=Alert Raised on: March
PS C:\src\t> $s | Where-Object { $_ -match '.*var5=(.*)\s+\w+:' } | ForEach-Object { $Matches[1] }
Alert Raised

Однако использование одного и того же кода powershell в сценарии оболочки cmd приводит к другому результату. Это почему? Есть ли что-то, что нужно экранировать для оболочки cmd?

C:>type mat002-annex.bat
@ECHO OFF
SET "S=Status 58   var5=Alert Raised on: March"
ECHO S is set to %S
FOR /F %%a IN ('powershell -NoLogo -NoProfile -Command ^
    " '%S%' | Where-Object { $_ -match '.*var5=(.*)\s+\w+:' } | ForEach-Object { $Matches[1] } "') DO (ECHO Result is "%%a")

C:>mat002-annex.bat
S is set to S
Result is "Alert"

Ответы [ 2 ]

0 голосов
/ 30 апреля 2018

PetSerAl , как он часто делает, предоставил критический указатель в комментарии:

Цикл

cmd.exe for /f по умолчанию разбивает свои входные строки на токены по пробелам , так что for /f %%a in (...) do ставит только на первое место такой токен в переменной %%a.

Это поведение по умолчанию можно изменить с помощью строки параметров : for /f "<options>" %%a in (...) do.
Запуск for /? из приглашения cmd.exe описывает его синтаксис:

    eol=c           - specifies an end of line comment character
                      (just one)
    skip=n          - specifies the number of lines to skip at the
                      beginning of the file.
    delims=xxx      - specifies a delimiter set.  This replaces the
                      default delimiter set of space and tab.
    tokens=x,y,m-n  - specifies which tokens from each line are to
                      be passed to the for body for each iteration.
                      This will cause additional variable names to
                      be allocated.  The m-n form is a range,
                      specifying the mth through the nth tokens.  If
                      the last character in the tokens= string is an
                      asterisk, then an additional variable is
                      allocated and receives the remaining text on
                      the line after the last token parsed.
    usebackq        - specifies that the new semantics are in force,
                      where a back quoted string is executed as a
                      command and a single quoted string is a
                      literal string command and allows the use of
                      double quotes to quote file names in
                      file-set.

Если вы хотите, чтобы каждая строка ввода записывалась в переменную single , у вас есть две опции:

Примечание. В приведенных ниже примерах используется следующая командная строка PowerShell, которая просто выводит строковый литерал с несколькими начальными, внутренними и конечными пробелами one two .

powershell -command " '   one   two   ' "

Чтобы упростить цитирование, ниже используется опция usebackq, которая позволяет встраивать команду в `...`.

Также обратите внимание, что хорошая практика - добавлять -NoProfile в powershell.exe командную строку , чтобы предотвратить ненужную - и потенциально изменяющую поведение - загрузку профиля пользователя; Я опущу это ниже для краткости.


"delims=": сохранение строки в точности как есть

@echo off

for /f "usebackq delims=" %%a in (`powershell -command " '   one   two   ' "`) do echo Result is "%%a"

Вышеуказанные выходы:

Result is "   one   two   "

Обратите внимание, как также сохранялись начальные и конечные пробелы.

Важно : чтобы delims= был признан деактивирующим синтаксическим анализом на основе разделителя (на основе разделителя), его необходимо поместить в самом конце строки параметров.


"tokens=*": обрезка ведущий пробел

@echo off

for /f "usebackq tokens=*" %%a in (`powershell -command " '   one   two   ' "`) do echo Result is "%%a"

Вышеуказанные выходы:

Result is "one   two   "

Обратите внимание, как ведущие пробелы были обрезаны .

Любопытно, что обрезка применяется только к начальным пробелам, и, похоже, также нет прямого способа обрезать концевые пробелы.

0 голосов
/ 29 апреля 2018

Вам не нужен цикл for в командном файле.

@ECHO OFF
SET "S=Status 58   var5=Alert Raised on: March"
powershell -NoLogo -NoProfile -Command " '%S%' | Where-Object { $_ -match '.*var5=(.*)\s+\w+:' } | ForEach-Object { $Matches[1] } "

Выше приведен ожидаемый результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...