Как правильно установить переменную из PowerShell в командном файле Windows? - PullRequest
0 голосов
/ 30 декабря 2018

По неизвестным причинам я не могу получить эту переменную в командном файле Windows.

PowerShell:

$datePattern = [Regex]::new('value=(\S+)')
$datePattern = [Regex]::new('(\d\d\.\d)')
$matches = $datePattern.Matches("/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /")
$matches.Value

Она отлично работает.Однако это с треском проваливается в пакетном файле.

for /f %%i in ("PowerShell -NoProfile -ExecutionPolicy Bypass -Command $datePattern = [Regex]::new(value=(\S+)); $datePattern = [Regex]::new((\d\d\.\d)); $matches = $datePattern.Matches(tmpFile); $matches.Value") do ( set newValue=%%i )

Цель состоит в том, чтобы иметь возможность %newValue% return 12.2 из value = .Если это можно сделать непосредственно в командном файле, то это даже лучше.Значения отличаются от файла к файлу.

Ответы [ 3 ]

0 голосов
/ 30 декабря 2018

Предоставляется файл tmpfile IS однострочный файл и не превышает максимальную длину строки cmd.

Пакет

:: Q:\Test\2018\12\30\SO_53977221_.cmd
@Echo off
set /P "string="<tmpfile
set "string=%string:*value=%"
set "newvalue=%string:~1,4%"
set newvalue

>  SO_53977221_.cmd
newvalue=12.2

Используется подстановка строки (с подстановочным знаком) и подстрока для получения требуемого значения.

Возможно также комбинированное решение для пакетной обработки / PowerShell, но для его экранирования и цитирования требуется немного больше усилий, чем для попытки.

Этот лайнер PowerShell one выдает

PoSh> if((Get-Content .\tmpfile) -match 'value=(\d\d\.\d)'){$Matches[1]}
12.2

Правильно упакованный в пакет

:: Q:\Test\2018\12\30\SO_53977221.cmd
@Echo off
for /f "usebackq" %%A in (`
    powershell -NoP -C "if((Get-Content .\tmpfile) -match 'value=(\d\d\.\d)'){$Matches[1]}"
`) Do set "newvalue=%%A"
set newvalue

Пример вывода:

> .\SO_53977221.cmd
newvalue=12.2
0 голосов
/ 30 декабря 2018

Это все о правильном цитировании и экранировании .Прочитайте powershell -? (отрывок урезан):

-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 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.

Здесь наши <command> содержат двойные кавычки:

$datePattern = [Regex]::new('(\d\d\.\d)');$matches = $datePattern.Matches("/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /");$matches.Value

Используйте вместо одинарных кавычек следующее:

$datePattern = [Regex]::new('(\d\d\.\d)');$matches = $datePattern.Matches('/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /');$matches.Value

или, альтернативно, двойные внутренние двойные кавычки дважды :

$datePattern.Matches(""""/ … / value=12.2 / … /"""")

Полный вызов PowerShell при этом выглядит следующим образом:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {$datePattern = [Regex]::new('(\d\d\.\d)');$matches = $datePattern.Matches(""""/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /"""");$matches.Value}"

Наконец, примените команду FOR /F Loop: к результатам другой команды :

for /f "usebackq" %i in (`PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {$datePattern = [Regex]::new('(\d\d\.\d)');$matches = $datePattern.Matches(""""/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /"""");$matches.Value}"`) do ( set "newValue=%i" )

Последняя команда работает из командной строки. Удвойте знак % в пакетном сценарии :

for /f "usebackq" %%i in (`PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {$datePattern = [Regex]::new('(\d\d\.\d)');$matches = $datePattern.Matches(""""/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /"""");$matches.Value}"`) do ( set "newValue=%%i" )
0 голосов
/ 30 декабря 2018

Я не совсем уверен, что именно вы хотите получить от регулярного выражения, но в своем коде вы переопределяете $datePattern сразу после установки его в value=(\S+).

с помощью\S+ Вы, похоже, не заботитесь о формате значения, если оно не является пробелом.Во втором определении регулярного выражения вы действительно хотите, чтобы значение было ровно двумя цифрами, за которыми следуют точка, а затем еще одна цифра.

Если вам нужен именно такой числовой формат, просто выполните

* 1009.*

При выполнении с

$m = $datePattern.Matches("/ start=2010 / height=1 / value=12.2 / length=0.60 / users=264 / best=Adam /")

у вас будет $m.Value, что приведет к value=12.2
и $m.Groups[1].Value, что даст вам результат 12.2

Если вы ищете числовое значение, но не знаете точный формат, лучше измените регулярное выражение на что-то вроде этого: 'value=(\d+.\d+)'

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