在 shell 脚本中执行的批处理文件不等待用户输入

Posted

技术标签:

【中文标题】在 shell 脚本中执行的批处理文件不等待用户输入【英文标题】:Batch file executed in shell script not waiting for user input 【发布时间】:2021-06-08 21:06:57 【问题描述】:

我偶然发现了 git-hooks 并试图创建一个在 Windows 上运行。所以我决定使用批处理文件来这样做,因为它看起来很容易。

首先,我将 pre-commit 示例重命名为 pre-commit 并在那里调用了我的 bat 步骤:

#!/bin/sh
$(pwd)/git-hooks/hooks/unit_test.bat &&
$(pwd)/git-hooks/hooks/integration_test.bat

unit_test.bat 只显示一些消息并运行单元测试任务,但 integration_test.bat 会提示用户是否要运行这些测试因为它们通常较慢。

问题在于提示(使用“choice”或“set /p”完成)没有得到用户输入

'set /p' 不等待用户输入 “选择”冻结,不允许任何用户输入

我尝试添加 start 来调用 .bat 文件,但它会在另一个 cmd 上打开它们,因此无法停止提交。

引用的文件

unit_test.bat

@echo off
echo ^> Testes unitários
call gradlew testReport || (echo(& echo Testes unitários falharam! Acesse o relatório de testes para conferir.& exit 1))

integration_test.bat

@echo off

echo(echo ^> Testes integrados
%SystemRoot%\System32\choice.exe /C sn /M "Esses testes geralmente são mais lentos. Quer rodar os testes integrados"
if ERRORLEVEL 2 goto nao
call gradlew integrationTests || (echo(echo Testes integrados falharam! Acesse o relatório de testes para conferir.) && exit 1)

:nao
echo(echo Não se esqueça de confirmar que os testes integrados passam antes de fazer o 'git push'!)
exit /B

【问题讨论】:

/bin/sh/bin/bash 不同,您实际上运行的是常规 shell 脚本而不是 bash 脚本,因为您的脚本调用的是 /bin/sh 解释器而不是 /bin/bash 解释器. bash 的路径在您的系统上可能不同,因此您可能需要运行 which bash 来确认它。 感谢您指出,那时我应该将其引用为 shell 脚本而不是 bash。这个细节是否也应该解决这种情况?我尝试使用 /bin/bash 解释器运行,但似乎没有帮助 我认为这不是你问题中的问题,但我会尽量确保所有细节尽可能准确,这就是我提到的原因。 这是一个很好的观点,感谢您指出这一点。 git 钩子没有交给 tty,如果你需要它,你必须自己重新打开它(尽管钩子期间的交互性有点 imo)——在 Windows 上,我相信它正在打开 @987654330 @ 【参考方案1】:

我认为gradlew 实际上是另一个批处理文件gradlew.bat,所以我假设,如果您希望它在完成后返回到脚本,您应该使用Call 命令。此外,您应该知道& 将两个单独的命令连接在一行上,而&& 仅在前一个命令成功时才运行一个命令。在您的情况下,Echo 命令不可能不成功,因此只需& 是必要的。此外,If ErrorLevel 1 表示如果错误代码为 1 或更高版本,这意味着,在您发布的代码中,代码将始终为 goto sim。您应该使用 If Not ErrorLevel 2If %ErrorLevel% Equ 1If "%ErrorLevel%" == "1"

示例:(请插入gradlew.bat 的完整路径,而不是依赖容易损坏或受影响的%Path% 变量,如果路径和可执行文件名称包含空格或有问题的字符,请用双引号引起来) .我已经删除了下面示例中不必要的连接,因为它在脚本中不是必需的。

unit_test.bat

@Echo Off
Echo ^> Testes unitários
Call gradlew.bat testReport || (Echo(& Echo Testes unitários falharam! Acesse o relatório de testes para conferir.& Exit 1)

integration_test.bat

@Echo Off
Echo(
Echo ^> Testes integrados
%SystemRoot%\System32\choice.exe /C sn /M "Esses testes geralmente são mais lentos. Quer rodar os testes integrados"
If Not ErrorLevel 2 GoTo sim
Echo(
Echo Não se esqueça de confirmar que os testes integrados passam antes de fazer o 'git push'!
Exit /B

:sim
Call gradlew.bat integrationTests || (
    Echo(
    Echo Testes integrados falharam! Acesse o relatório de testes para conferir.
)
Exit 1

或:

@Echo Off
Echo(
Echo ^> Testes integrados
%SystemRoot%\System32\choice.exe /C sn /M "Esses testes geralmente são mais lentos. Quer rodar os testes integrados"
If ErrorLevel 2 GoTo nao
Call gradlew.bat integrationTests || (
    Echo(
    Echo Testes integrados falharam! Acesse o relatório de testes para conferir.
)
Exit 1

:nao
Echo(
Echo Não se esqueça de confirmar que os testes integrados passam antes de fazer o 'git push'!
Exit /B

根据您使用的某些字符,我还建议您确保使用适当的代码页(可能是 1252)运行脚本。

【讨论】:

感谢您纠正我的错误并以清晰的方式解释它们,这将有助于知道错误可能不是因为这些更改后的脚本语法。我将编辑原始帖子。然而,当用户必须写下他们的选择时,冻结问题仍然存在。也许我忘了添加一些有意义的东西来帮助人们重现它。【参考方案2】:

正如@AnthonySotille 指出的那样,冻结错误是由于 git-hooks 禁用交互性造成的。

我通过将提示提取到另一个 .bat 文件并使用 start /wait 调用它们来绕过这种情况。这会打开另一个 cmd,运行提示符,然后使用成功代码表示 Y 并将失败代码表示为 N 退出。这似乎不是一个好的做法,但现在,它可以完成这项工作。

此问题可能被视为与How do I prompt the user from within a commit-msg hook? 重复

【讨论】:

以上是关于在 shell 脚本中执行的批处理文件不等待用户输入的主要内容,如果未能解决你的问题,请参考以下文章

jenkins执行shell脚本,使用scp免密传输失败问题

Shell脚本

Linux。。shell 脚本中经常要用到ssh。可是ssh又要交互式输密码。怎么能不交互的输密码呢?

shell脚本条件语句练习

我的 perl 脚本如何调用和执行并后处理它

与 shell 脚本不同,批处理文件是不可执行的吗?