我正在试验管道.所以我创建了一个简单的批处理文件(dos/windows),如下所示:
@echo off
echo [+] starting batch file
:start
set /p msg="[+] enter msg: "
echo [+] Your message: %msg%
IF "%msg%"=="x" (
echo [x] end loop
goto exit
) ELSE (
goto start
)
:exit
echo [+] bye
Run Code Online (Sandbox Code Playgroud)
只要我从命令行调用它,这个工作正常:
> showAll.bat
S:\80_personalFolder\81_lab\python\ghoul>showAll.bat
[+] starting batch file
[+] enter msg: hello
[+] Your message: hello
[+] enter msg: x
[+] Your message: x
[x] end loop
[+] bye
S:\80_personalFolder\81_lab\python\ghoul>
Run Code Online (Sandbox Code Playgroud)
但是一旦我尝试将输入传递给它,它将在一个无限循环中运行:
> echo hello | showAll.bat
Run Code Online (Sandbox Code Playgroud)
将导致:
[...]
[+] enter msg: [+] Your message: hello
[+] enter msg: [+] Your message: hello
[+] enter msg: [+] Your message: hello
[+] enter msg: [+] Your message: hello
[+] enter msg: [+] Your message: hello
[...]
Run Code Online (Sandbox Code Playgroud)
我不明白这种行为.有人可以解释我监督的内容或我错过的内容!我如何解决这个问题,所以它不会无限期地运行,但会在循环中的下一个提示停止,所以我可以手动退出?
UPDATE!首先感谢我收到的非常好的答案.它帮助我更好地理解发生了什么.所以我修改了代码以在再次调用read之前重置输入var.我想要实现的目标如下:1)一旦脚本从管道输入运行hello并重新进入循环,将管道'echo hello'发送到批处理脚本2)... ...我希望能够手动输入别的东西.相反,它仍将使用脚本将变量设置为的默认值进行无限循环.如何停止管道并切换回默认的标准输入?我想这就是我正在努力解决的真正问题.我甚至不确定这可以做到.
谢谢,最好
该set /p var=命令旨在检索要存储到指示变量中的输入数据.行为是
set /p失败(没有错误)并且变量不会更改.第二种情况是您所看到的行为的来源.
echo在第一次迭代中读取"hello"(来自命令)您的代码(仅检查变量内容)没有看到两种情况之间的差异,因为变量仍保留上一次迭代的数据.
如果没有读取任何数据是循环退出的有效案例,你可以做类似的事情
:start
set "msg="
set /p msg="[+] enter msg: "
if not defined msg goto :exit
Run Code Online (Sandbox Code Playgroud)
如果没有读取数据,则在每次读取和离开之前重置变量.
这也可以用更简单的方式编写
:start
set /p msg="[+] enter msg: " || goto :exit
Run Code Online (Sandbox Code Playgroud)
这使用条件运算符||(如果前一个命令失败,则执行next命令)如果失败则离开循环set /p.
编辑以适应评论:
所需的行为是从命令中存在的管道读取数据,但是当读取数据时,set /p应该从用户检索数据.首先,我们需要看看管道是如何工作的.
当cmd处理管道运营商,创建了两个新的独立进程来处理管道的左侧和右侧.
此时,我们有三个cmd实例(OP问题中的情况):
cmd1 :附加到运行typed命令的控制台 cmd2 :在管道的左侧运行命令cmd3 :在管道的右侧运行批处理文件与每个实例关联的输入/输出流(stdin是输入流,stdout是输出流)是:
cmd1:stdin是当前的控制台stdin,stdout是当前的控制台stdoutcmd2:stdin从中继承控制台cmd1,stdout附加到stdin流中cmd3cmd3:stdin附加到stdout流cmd2,stdout是继承自cmd1在此方案中cmd3,处理批处理文件无法访问活动的控制台stdin流cmd1或cmd2.
所以,在这一点上,我没有看到实现指示行为的方法.
对于您的示例,当您只接受管道中的一根管线时,很容易修复它。我只添加了“set“msg=x””来将默认值每次重置为“x”,因为set /p当没有新输入时不会更改变量。
并且set /p不在管道上下文中等待(只是非常正确)
@echo off
echo [+] starting batch file
:start
set "msg=x"
set /p msg="[+] enter msg: "
echo [+] Your message: %msg%
IF "%msg%"=="x" (
echo [x] end loop
goto exit
) ELSE (
goto start
)
:exit
echo [+] bye
Run Code Online (Sandbox Code Playgroud)