从子程序返回变量,不工作......为什么?

时间:2013-08-05 07:43:10

标签: windows batch-file

为了在文本文件的变量中存储多行,我使用的是这个问题的答案:https://stackoverflow.com/a/10624240/1513458

使用此脚本内联并解析大文件给了我最大的setlocal错误。因此,为了解决这个问题,我将脚本放在子程序中,并从我需要的行中调用它。

子例程底部的回显在它终止之前会输出预期的结果很好......但是回到它最初调用的顶部,变量是空的。那是为什么?

以下是该脚本的缩短版本:

setlocal EnableDelayedExpansion
set sourcefile=cc1
call :readfile %sourcefile%
echo !insert!
goto :EOF

:readfile
SETLOCAL DisableDelayedExpansion
set "insert="
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ %SOURCELOC%\%1.txt"`) do (
    set "line=%%a"
    SETLOCAL EnableDelayedExpansion
    set "line=!line:#=#S!"
    set "line=!line:*:=!"
    for /F "delims=" %%p in ("!insert!#L!line!") do (
        ENDLOCAL
        set "insert=%%p"
    )
)
SETLOCAL EnableDelayedExpansion
if defined insert (
set "insert=!insert:~2!"
set ^"insert=!insert:#L=^

!"
set "insert=!insert:#S=#!"
)
rem A echo !insert! here would output the expected result
goto :EOF

非常感谢你的帮助。批量显然不适合我,但我需要坚持这一点。

2 个答案:

答案 0 :(得分:3)

您的:readfile例程顶部有SETLOCAL,用于本地化环境更改。例程结束时,为在例程中实例化的每个活动SETLOCAL执行隐式ENDLOCAL。因此,环境将恢复到呼叫之前存在的状态。

不需要被调用的子程序。您的早期代码必须在FOR循环中没有ENDLOCAL的SETLOCAL。这将导致最大SETLOCAL错误。现在你的FOR循环已配对SETLOCAL / ENDLOCAL,所以不再有问题。

可以在ENDLOCAL屏障上传输任何值,但它使用了一种先进的技术。

一些简单的重组避免了这样做的必要性。但要小心 - 没有批处理变量可以包含超过8192个字符。

setlocal disableDelayedExpansion
set sourcefile=cc1

set "insert="
for /f "delims=" %%a in ('findstr /n "^" "%SOURCELOC%\%~1.txt"') do (
  set "line=%%a"
  setlocal EnableDelayedExpansion
  set "line=!line:#=#S!"
  set "line=!line:*:=!"
  for /f "delims=" %%p in ("!insert!#L!line!") do (
    endlocal
    set "insert=%%p"
  )
)
setlocal EnableDelayedExpansion
if defined insert (
set "insert=!insert:~2!"
set ^"insert=!insert:#L=^

!"
set "insert=!insert:#S=#!"
)
echo !insert!


修改

这是一个解决方案,演示了在ENDLOCAL边框上返回任何值(除了它不支持回车。有一个支持回车的简单扩展)。该例程将给出正确的结果,无论是在启用还是禁用延迟扩展的情况下调用它。该技术由DosTips用户jeb在此处开发:http://www.dostips.com/forum/viewtopic.php?f=3&t=1839,此处:http://www.dostips.com/forum/viewtopic.php?p=6930#p6930。在那里你会找到一些关于它是如何工作的解释,但它不适合胆小的人。

@echo off
setlocal enableDelayedExpansion
set sourceloc=.
set sourcefile=test
set ^"LF=^

^"
call :readFile "%sourcefile%"
echo(!insert!
exit /b

:readFile
setlocal
set "notDelayed=!"

setlocal disableDelayedExpansion
set "insert="
for /f "delims=" %%a in ('findstr /n "^" "%SOURCELOC%\%~1.txt"') do (
  set "line=%%a"
  setlocal EnableDelayedExpansion
  set "line=!line:%%=%%J!"
  set "line=!line:*:=!"
  for /f "delims=" %%p in ("!insert!%%~L!line!") do (
    endlocal
    set "insert=%%p"
  )
)
setlocal enableDelayedExpansion
if defined insert (
  set "insert=!insert:"=%%~K!"
  if not defined notDelayed set "insert=!insert:^=^^^^!"
)

if defined insert if not defined notDelayed set "insert=%insert:!=^^^!%" Do not remove!
set "replace=%% """"
for %%L in ("!LF!") do for /f "tokens=1,2" %%J in ("!replace!") do (
  endlocal
  endlocal
  endlocal
  set "insert=%insert%" Do not remove!
)
exit /b

答案 1 :(得分:0)

试试这个:

setlocal EnableDelayedExpansion
set sourcefile=cc1
call :readfile insert
echo %insert%
goto :EOF

:readfile
SETLOCAL DisableDelayedExpansion
set "insert="
FOR /F "delims=" %%a in ('findstr /n "^" "%SOURCELOC%\%1.txt"') do (
     set "line=%%a"
     SETLOCAL EnableDelayedExpansion
     set "line=!line:#=#S!"
     set "line=!line:*:=!"
     for /F "delims=" %%p in ("!insert!#L!line!") do (
          ENDLOCAL
          set "insert=%%p"
     )
)
SETLOCAL EnableDelayedExpansion
if defined insert (
set "insert=!insert:~2!"
set ^"insert=!insert:#L=^

!"
set "insert=!insert:#S=#!"
)
rem A echo !insert! here would output the expected result
SET "%1=!insert!"
ENDLOCAL 
goto :EOF