在批处理脚本中将多个值管道化为程序

时间:2014-12-23 14:36:45

标签: batch-file command-prompt piping

我正在编写自己的简单系统,允许我在将APK上传到GPlay之前自动对其进行签名。我有一个批处理文件可以进行签名;和#34;包装"批处理文件,其内容将由Jenkins post-build在命令行上运行。

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

This article向我展示了如何将值传递给程序。引用答案,:

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

帮助?

3 个答案:

答案 0 :(得分:4)

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解析器通过放置&amp;每个命令之间。不幸的是,解析器还插入了一些额外的空格。所以管道的左侧变成了类似的东西:

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

现在,您可以轻松查看不需要的尾随空格的来源。有关如何实现管道的更多信息,请参阅Why does delayed expansion fail when inside a piped block of code?

我终于想出了一个解决方案。我创建了一个名为WriteArgs.bat的辅助批处理脚本,只是ECHO传递给它的每个参数。

<强> 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在这里正常工作,但不能用于原始命令。但这确实解决了问题: - )

更新 - 嗯,它解决了我机器上的问题。但这似乎是一个时间问题,我不相信任何给定的管道解决方案将始终有效。我觉得唯一的解决方案是使用临时文件和重定向的解决方案。

答案 1 :(得分:1)

您知道,最简单的解决方案是提供jobaliasmobilewear作为脚本参数,而不是尝试将它们传输到stdin。如果您希望以不带参数的方式以交互方式运行,那么如果未定义,您仍然可以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

答案 2 :(得分:1)

它是set /p的问题,它读取输入缓冲区,但是当多行可用时它无法拆分此缓冲区,它只是从缓冲区获取第一行,其余的将被丢弃

对于单个echo管道传输到单个set/p,这不是问题,但当您将更多行传输到多个set/p时,您会得到随机结果。

dbenham的解决方案可以工作,但它取决于你的系统!
由于两个进程(行生成器和set/p使用者)在自己的cmd.exe任务中同步运行,它取决于每个进程获得的CPU时间。

但是,您可以通过morefindstr等其他程序拆分内容来确保正确使用。
因为这些将输入缓冲区在线路边界处进行探测。