在处理一个有趣的批处理文件时遇到了一些问题



所以我只是一个普通人,发现你可以用批处理做一些有趣的事情。无论如何,我正试图为一个朋友在usb上做一个很酷的隐藏文件夹类型的交易。

唯一的问题是,我真的想让它把问题打出来,就像它是一个真正的人工智能或人在问一样。我在这里找到了一个现实打字的解决方案。链接

这是解决方案示例

@echo off
:: Ghost typer
setlocal enableextensions enabledelayedexpansion
set lines=6
set "line1=Twinkle twinkle little star"
set "line2=How I wonder what you are"
set "line3=Up above the world so high"
set "line4=Like a diamond in the sky"
set "line5=Twinkle twinkle little star"
set "line6=How I wonder what you are"
for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
for /L %%a in (1,1,%lines%) do set num=0&set "line=!line%%a!"&call :type
pause>nul
goto :EOF
:type
set "letter=!line:~%num%,1!"
set "delay=%random%%random%%random%%random%%random%%random%%random%"
set "delay=%delay:~-6%"
if not "%letter%"=="" set /p "=a%bs%%letter%" <nul
:: adjust the 3 in the line below: higher is faster typing speed
for /L %%b in (1,3,%delay%) do rem
if "%letter%"=="" echo.&goto :EOF
set /a num+=1
goto :type

所以我只是用我自己的线代替了这条线。。"输入密码.."确保将其设置为一行。

但这就是我遇到问题的地方。这似乎是一个循环什么的。每当我试图让它进入一组新的命令时,它就会破坏整个过程。我在哪里可以添加goto来启动新的命令?

如果我完全理解你在文章和评论中描述的问题,那么你似乎还没有完全理解你的代码。我将(尝试)解释一下为什么cmd解释器永远无法访问脚本中的某些位置。结果是,这些地方的代码永远不会被执行。

让我们考虑一下代码的第一部分(cmd解释器从哪里开始):

@echo off
:: Ghost typer
setlocal enableextensions enabledelayedexpansion
set lines=6

set "line1=Twinkle twinkle little star"
set "line2=How I wonder what you are"
set "line3=Up above the world so high"
set "line4=Like a diamond in the sky"
set "line5=Twinkle twinkle little star"
set "line6=How I wonder what you are"

for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
for /L %%a in (1,1,%lines%) do set num=0&set "line=!line%%a!"&call :type
pause>nul
goto :EOF

您可以使用@echo off禁用每个命令的打印,启用延迟扩展,设置包含每一行文本的所有变量,使用for /f循环来获得在键入文本时将使用的退格字符(我不太明白为什么prompt命令与for循环和双引号一起使用),并使用for /L循环来迭代所有lines,并通过调用脚本第二部分中实现的:type函数来键入它们。之后,pause>nul将使控制台等待,直到用户按下某个键。最后,goto :EOF用于终止当前批处理脚本的执行(或"上下文",请参阅更多信息),否则cmd解释器将继续执行:type子例程下的代码一段额外的时间(这很可能不是您的意图)。如Microsoft的goto命令文档中所述,:EOF是一个预定义的标签,可用于退出当前批处理脚本。因此,无论您放在goto :EOF下的内容都不会被执行,或者至少不会在同一个"上下文"中执行(请参阅进一步了解"同一上下文"的含义)。

但是,为什么:type子例程被执行,而那里的goto :EOF没有退出您的批处理脚本?

:type
set "letter=!line:~%num%,1!"
set "delay=%random%%random%%random%%random%%random%%random%%random%"
set "delay=%delay:~-6%"
if not "%letter%"=="" set /p "=a%bs%%letter%" <nul
:: adjust the 3 in the line below: higher is faster typing speed
for /L %%b in (1,3,%delay%) do rem
if "%letter%"=="" echo.&goto :EOF
set /a num+=1
goto :type

这要归功于call命令。:type和其他标签一样只是一个标签,但我之所以称它为子程序,是因为你使用call而不是goto来执行它下面的内容。goto只会跳到你给它的标签上,忘记它在goto之前做了什么。另一方面,call命令将在执行脚本的上下文之上创建一个新上下文。这样,当新上下文关闭并退出时,可以回到call之前脚本的执行停止的位置(有点像从子例程调用和返回)。要退出该上下文,cmd解析器需要遇到一个正常的(脚本)文件结尾,一个显式的exit命令,或者在本例中,一个goto :EOF。但是,即使在:type子程序的上下文中,也不会执行goto :type以下的代码。事实上,在:type标签下的for /L之后有两种情况:

  1. 任一%letter%为空:在这种情况下,将打印空行(echo.),并且上下文将因goto :EOF而关闭。这意味着它将返回到脚本的上下文(在那里它将继续for /L迭代文本)
  2. 或者%letter%不为空:然后变量num递增,cmd解释器跳回:type标签(因为goto :type),而从未到达goto :type下的代码(得到gotocall之间的差?如果是call,它会在某个时刻执行它下的代码)

现在我可以向您展示哪些地方可以添加必须执行的代码,哪些地方根本不会执行代码,除非如果您在这些地方放置标签,并在可以添加代码的区域使用gotocall(注意差异和危险)。我还修改了您使用&for /Lif&会使您的代码更加不可读。在您的情况下,它们并不是真正需要的,所以我将每个命令放在自己的行中,并用(...)将命令括起来。

@echo off
:: Ghost typer
setlocal enableextensions enabledelayedexpansion
set lines=6

set "line1=Twinkle twinkle little star"
set "line2=How I wonder what you are"
set "line3=Up above the world so high"
set "line4=Like a diamond in the sky"
set "line5=Twinkle twinkle little star"
set "line6=How I wonder what you are"

for /f %%a in ('"prompt $H&for %%b in (1) do rem"') do set "BS=%%a"
REM Here is place OK 1
REM Gets executed before the text prints
for /L %%a in (1,1,%lines%) do (
set num=0
set "line=!line%%a!"
call :type
)
REM Here is place OK 2
REM Gets executed after the text prints
pause>nul
goto :EOF
! THIS PART IS NEVER REACHED BY THE CMD-INTERPRETER !
:type
set "letter=!line:~%num%,1!"
set "delay=%random%%random%%random%%random%%random%%random%%random%"
set "delay=%delay:~-6%"
if not "%letter%"=="" set /p "=a%bs%%letter%" <nul
:: adjust the 3 in the line below: higher is faster typing speed
for /L %%b in (1,3,%delay%) do rem
if "%letter%"=="" (
echo.
REM Place OK 3
REM Here can come code that gets executed after each line is printed
goto :EOF
)
set /a num+=1
goto :type
! THIS PLACE WILL NEVER BE REACHED BY THE CMD-INTERPRETER EITHER !

我希望这篇长文能有所帮助。如果你有任何问题,请不要犹豫。

祝你好运!

最新更新