Передача нескольких значений в программу в пакетном сценарии

Я пишу свою собственную простую систему, позволяющую автоматически подписывать APK-файлы перед их загрузкой в ​​GPlay. У меня есть командный файл, который подписывает; и пакетный файл «оболочки», содержимое которого будет запускаться в командной строке после сборки Jenkins.

sign_apks.bat:

@echo off

set /p job= "Enter job name: "
set /p alias= "Enter key alias: "
set /p mobile= "Sign mobile? (y/n): "
set /p wear= "Sign wear? (y/n): "

echo.
echo "%job%"
echo "%alias%"
echo "%mobile%"
echo "%wear%"

[the rest of the code is sensitive so is emitted, but these variables are used later]

код оболочки:

@echo off

(echo test
echo test
echo y
echo y)| call sign_apks.bat

Эта статья показала мне, как передавать значения в программу. Цитата из ответа:

Multiple lines can be entered like so:

(echo y
echo n) | executable.exe

...which will pass first 'y' then 'n'.

Однако это не работает. Это вывод, который я получаю при запуске кода оболочки:

Enter job name: Enter key alias: Sign mobile? (y/n): Sign wear? (y/n):
"test "
""
""
""

Помощь?


person J15t98J    schedule 23.12.2014    source источник


Ответы (3)


Вы знаете, самым простым решением было бы указать job, alias, mobile и wear в качестве аргументов сценария, а не пытаться передать их на стандартный ввод. Вы все еще можете set /p, если не определено, если хотите работать в интерактивном режиме без аргументов.

@echo off
setlocal

set "job=%~1"
set "alias=%~2"
set "mobile=%~3"
set "wear=%~4"

if not defined job set /p "job=Enter job name: "
if not defined alias set /p "alias=Enter key alias: "
if not defined mobile set /p "mobile=Sign mobile? (y/n): "
if not defined wear set /p "wear=Sign wear? (y/n): "

echo.
echo "%job%"
echo "%alias%"
echo "%mobile%"
echo "%wear%"

Затем, когда вы call sign_apks.bat, просто назовите это так:

call sign_apks.bat test test y y
person rojo    schedule 23.12.2014
comment
Не думал об этом. Большое спасибо :) - person J15t98J; 24.12.2014

Есть что-то очень странное в том, как SET /P взаимодействует с вашим конвейерным вводом, что я не совсем понимаю.

Но у меня есть несколько решений :-)

Самое простое решение — записать ваши ответы во временный файл, а затем использовать этот временный файл в качестве перенаправленного ввода.

@echo off
(
  echo test
  echo test
  echo y
  echo y
)>responses.temp
call sign_apks.bat <responses.temp
delete responses.temp

Вот так бы я решил вашу проблему. Но некоторые люди не любят использовать временные файлы (почему не знаю). Поэтому я решил попытаться решить эту проблему, используя канал без временного файла.

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

@echo off
(
  call echo test1
  call echo test2
  call echo y1
  call echo y2
) | sign_apks.bat

--ВЫХОД--

Enter job name: Enter key alias: Sign mobile? (y/n): Sign wear? (y/n):
"test1 "
"test2 "
"y1 "
"y2 "

Я не могу объяснить, почему CALL позволяет правильно работать каждому из операторов SET /P. Но я могу объяснить, почему к каждому значению добавляется пробел. Это связано с тем, почему CALL не нужен, когда вы используете пакетный скрипт с каналом.

Каждая сторона канала выполняется в новом сеансе cmd.exe. Например, правая сторона канала становится командой, которая выглядит примерно так:

C:\Windows\system32\cmd.exe /S /D /c" sign_apks.bat"

По этой причине CALL не нужен - управление вернется после завершения нового сеанса cmd.exe.

Нежелательные пробелы являются артефактом того, как конвейеры обрабатывают блоки в скобках. Синтаксический анализатор должен захватить весь переданный блок кода и преобразовать его в одну строку, которую можно включить в аргумент CMD.EXE /C. Синтаксический анализатор CMD.EXE делает это, помещая & между каждой командой. К сожалению, парсер также вставляет лишние пробелы. Таким образом, левая сторона трубы превращается во что-то вроде:

C:\Windows\system32\cmd.exe /S /D /c" ( call echo test & call echo test & call echo y & call echo y )"

Теперь вы можете легко увидеть, откуда берутся нежелательные конечные пробелы. Дополнительную информацию о реализации каналов см. в разделе Почему отложенное расширение завершается сбоем внутри переданного блока кода?.

Наконец-то я придумал еще одно решение. Я создал вспомогательный пакетный скрипт под названием WriteArgs.bat, который просто повторяет каждый переданный ему аргумент.

WriteArgs.bat

@echo off
:loop
if .%1 equ . exit /b
echo %1
shift /1
goto loop

С помощью этого простого пакетного скрипта теперь вы можете решить свою проблему, используя:

WriteArgs.bat test test y y | sign_apks.bat

Опять же, я не понимаю, почему SET /P работает правильно здесь, но не работает с вашей исходной командой. Но это решает проблему :-)

Обновление – Ну, оно решает проблему на моей машине. Но, похоже, это проблема времени, и я не уверен, что какое-либо заданное конвейерное решение всегда будет работать. Единственное решение, которое я считаю надежным, — это то, которое использует временный файл и перенаправление.

person dbenham    schedule 23.12.2014
comment
Причина, по которой CALL-эхо работает, проста: оно медленнее. Это также причина, по которой эхо не работает с SET /p. Но вы находите хорошие обходные пути - person jeb; 23.12.2014
comment
@jeb - Хороший вопрос, CALL определенно замедляет левую сторону. Сначала я подумал, что это проблема времени. Но я до сих пор не могу уложить это в голове. Я не могу полностью объяснить все наблюдаемое поведение. Если левая сторона быстрее правой, то почему SET/P не останавливается на первой новой строке, чтобы следующий SET/P мог прочитать следующую строку? Без CALL он ведет себя так, как если бы первый SET /P считывал все строки ввода, но сохранял только первую. - person dbenham; 23.12.2014
comment
Я создам тему на dostips для этого, я некоторое время играл с этими проблемами - person jeb; 23.12.2014
comment
@jeb - жду твоего объяснения. Меня раздражает поведение SET /P. - person dbenham; 23.12.2014
comment
Тема, в которой обсуждается странное поведение, находится по адресу set /p, проблемы с каналами - person jeb; 24.12.2014

Это проблема set /p, он читает входной буфер, но не может разделить этот буфер, когда доступно несколько строк, он просто берет первую строку из буфера, а остальные будут отброшены.

Это не проблема для одного echo, переданного в один set/p, но когда вы передаете больше строк нескольким set/p, вы получаете случайные результаты.

Решение dbenham может сработать, но это зависит от вашей системы!
Поскольку оба процесса (линейный производитель и set/p потребитель) синхронно выполняются в собственной задаче cmd.exe, это зависит от процессорного времени, которое получает каждый процесс.

Но вы можете обеспечить правильное потребление, разделив содержимое другой программой, такой как more или findstr.
Поскольку они разделяют входной буфер строго по границам строк.

person jeb    schedule 23.12.2014
comment
Но SET /P не имеет проблем с несколькими строками перенаправленного ввода. Для меня это означает, что метод, с помощью которого SET /P считывает переданный ввод, должен сильно отличаться от того, как он считывает перенаправленный ввод. Это просто кажется странным. - person dbenham; 23.12.2014