单行嵌套循环

问题描述 投票:0回答:1

我正在尝试用单线 cmd /c 以获得一个没有分支的内部循环(实际上我有showLines例程来执行循环)。(实际上我有showLines例程来执行循环。)我知道它的性能最差,但我想知道是否有可能让它运行时不加引号。目前,它引发了"%G was unexpected at this time "的错误,所以,它需要一些正确的转义。所以,它需要一些正确的转义或扩展变量。

@echo off

setlocal enableDelayedExpansion

set "param=%~1"

netstat -aonb | findstr /n $ > tmpFile_Content


for /F "tokens=*" %%A in ('type tmpFile_Content ^| findstr /r /c:"%param%" /i') do (

  SET line=%%A

  for /F "tokens=1 delims=:" %%I in ("!line!") DO (
      set /a LineNum=%%I
      rem set /a NextLineNum=LineNum+1

  )

  set /a lineNum=!LineNum!-1 


  if !lineNum!==0 ( set param="tokens=*" ) else ( set param="tokens=* skip=!lineNum!" )
  rem FOLLOWING WORKS FINE in quotes
  cmd /q /v:on /c "@echo off && setlocal enableDelayedExpansion && set cnt=2 && for /F %%param%% %%B in (tmpFile_Content) do ( echo %%B && set /a cnt-=1 >nul && if ^!cnt^!==0 exit /b )"

  rem Following does not work even though cmd should take the rest of arguments after /c
  cmd /q /v:on /c setlocal enableDelayedExpansion && FOR /F "tokens=*" %%C IN ('echo !param!') DO ( for /F %%C %%G in (tmpFile_Content) do (  echo %%G && set /a cnt-^=1 >nul && if ^!cnt^!==0 exit /b ))

  rem call :showLines !LineNum!

 )

del tmpFile_Content

goto :eof

:showLines
  set /a lineNum=%1-1
  set cnt=2
  for /F "tokens=* skip=%lineNum%" %%B in (tmpFile_Content) do (
    echo %%B
    set /a cnt-=1
    if !cnt!==0 goto exitLoop
  )
  :exitLoop
  exit /b



windows batch-file cmd
1个回答
2
投票

要构建带有可变参数的for循环,你基本上需要把它们定义为一个宏来执行。例如,你可以用一个宏来定义和执行它们。

@Echo Off & Setlocal ENABLEdelayedExpasnion
Set param="tokens=* delims="
Set "test=string line"
Set For=For /F %param% %%G in ("^!test^!") Do echo %%G
%For%

当然,你可以更进一步,用另一个for循环宏来构建整个for循环。

UPDATE:

  • 定义命令的条件连接的方法现在已经被证明了
  • 简化了语法,允许常规扩展和代码块内的使用形式相同,让构造函数宏在构造新的for循环后调用一个子程序来扩展。
  • 简化了延迟连接变量的用法,以避免转义要求。
@Echo off
::: { Macro Definition
Setlocal DisabledelayedExpansion
    (set \n=^^^
%= This creates an escaped Line Feed - DO NOT ALTER =%
)
::: [ For Loop Constructor macro. ] For advanced programmers who need to use dynamic for loop options during code blocks.
::: - usage: %n.For%{For loop options}{variable set}{For Metavariable}{commands to execute}
::: - use delayed !and! variable to construct concatenated commands in the new for loop.
    Set n.For=For %%n in (1 2) Do If %%n==2 (%\n%
        Set FOR=%\n%
        For /F "tokens=1,2,3,4 Delims={}" %%1 in ("!mac.in!") Do (%\n%
            Set "FOR=For /F %%1 %%3 in ("!%%2!") Do (%%~4)"%\n%
        )%\n%
        Call :Exc.For%\n%
    )Else Set mac.in=
    Set "and.=&&"
    Set "and=!and.!"
::: } End macro definition.
    Setlocal EnableDelayedExpansion& rem // required to expand n.For constructor macro
::: - Usage examples:
    Set "example=is a string line"
    %n.For%{"tokens=* delims="}{example}{%%G}{Echo/%%~G}
    %n.For%{"tokens=1,2,3,4 delims= "}{example}{%%G}{"Echo/%%~J %%~G %%~H %%~I !and! Echo/%%~I %%~G %%~H %%~J"}
    Set "example2=Code block example"
    For %%a in (1 2 3) do (
        %n.For%{"Tokens=%%a Delims= "}{example2}{%%I}{"For /L %%# in (1 1 4) Do (Set %%I[%%#]=%%a%%#) !and! Set %%I[%%#]"}
    )
    Pause > Nul
    Goto :EOF
:Exc.For
    %FOR%
Exit /B

示例输出。

is a string line
line is a string 
string is a line
Code[1]=11
Code[2]=12
Code[3]=13
Code[4]=14
block[1]=21
block[2]=22
block[3]=23
block[4]=24
example[1]=31
example[2]=32
example[3]=33
example[4]=34

0
投票

最后,我想出了下面的方法来执行字符串中给出的代码,供有兴趣的人实验,也可能是为了了解一些关于转义和扩展的见解。

我使用了宏而不是cmd,我想这将会更快(不确定,因为据说 "调用 "也会导致cmd的启动)。

所以,这是一个简单的单行本,没有很多额外的代码。但事情很容易变得复杂,如果使用了额外的转义和特殊字符,那么@T3RR0R的宏程序将是必要的。

@echo off

setlocal EnableDelayedExpansion

set "param=%~1"

netstat -aonb | findstr /n $ > tmpFile_Content


for /F "tokens=*" %%A in ('type tmpFile_Content ^| findstr /r /c:"%param%" /i') do (

  SET line=%%A

  for /F "tokens=1 delims=:" %%I in ("!line!") DO (
      set /a LineNum=%%I
      rem set /a NextLineNum=LineNum+1

  )

  set /a lineNum=!LineNum!-1 


  rem CORRECT QUOTING
  if !lineNum!==0 ( set "param="tokens=*"" ) else ( set "param="tokens=* skip=!lineNum!"" )
  rem FOLLOWING WORKS FINE in quotes
  rem cmd /q /v:on /c "set cnt=2 && for /F ^!param^! %%B in (tmpFile_Content) do ( echo %%B && set /a cnt-=1 >nul && if ^!cnt^!==0 exit /b )"

  rem For reading !cnt! use !x!cnt!x!.
  rem Only one extra variable used, and in routine its replaced with !(exclamation) for our "cnt" variable.
  set "x=^!x^!"
  call :ExecCode "set cnt=2 && for /F ^!param^! %%%%B in (tmpFile_Content) do (echo %%%%B && set /a cnt=!x!cnt!x!-1 >nul && if !x!cnt!x!==0 (exit /b) )"

  rem call :showLines !LineNum!

 )

del tmpFile_Content

goto :eof

:ExecCode
  setlocal

  rem Replace with exclamation for variable
  set "x=^!"
  set "s=%~1"

  %s%

  endlocal
  exit /b  


:showLines
  set /a lineNum=%1-1
  set cnt=2
  for /F "tokens=* skip=%lineNum%" %%B in (tmpFile_Content) do (
    echo %%B
    set /a cnt-=1
    if !cnt!==0 goto exitLoop
  )
  :exitLoop
  exit /b

© www.soinside.com 2019 - 2024. All rights reserved.