[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[系统相关] [己解決]批处理命令 call 無法傳值?

本帖最后由 dreamer 于 2024-6-10 08:42 编辑

問題描述:下方批次檔是將Office 零售轉大量授權的工具,由於要自動化所以製作一個呼叫他的批次檔
  1. Call "%~pd0C2R-R2V-AIO.cmd"
  2. Echo %_msg%&Rem C2R-R2V-AIO檔的變數
复制代码
在C2R-R2V-AIO的1481行是離開批次的處理段落,有試著在1487行前加上
  1. endlocal&Set _msg=%_msg%
复制代码
但卻沒有效果,這個問題困擾了我一週,最終還是沒有找到答案,目前推測可能是過多的exit /b 跟 goto 所以造成非預期的現象,但還是想了解真正的原因而不是推測,希望有高手能給出更合理的分析,謝謝。
這個問題目前暫時用doskey+findstr解決(思路是將結果放到doskey後再用findstr判斷結果是否為finished=Finished),由於代碼過長貼不下源代碼如下
來源:https://github.com/abbodi1406/C2R-R2V-AIO

脚本太复杂,没看明白意思,大概理了下退出的代码
第1是 104行之前 多个 goto :e_  后退出,这之前没有定义msg。可以忽略。
第2是 104行之后 第117行,if 语句两个call 其中定义了msg,并在141行退出。故可以试试在141行之前添加一行
  1. endlocal & set _msg=%msg%
复制代码
bat小白,请多指教!谢谢!

TOP


未见源代码,但若在复合语块,如 for...do() 或 if...() 中用 endlocal&set _msg=%_msg% 这类 ‘续命’ 的玩法,会被 ‘预处理’ 提前毙掉的...

TOP

本帖最后由 newswan 于 2024-6-8 20:14 编辑
  1. Call "%~pd0C2R-R2V-AIO.cmd" _msg
  2. Echo %_msg%&Rem C2R-R2V-AIO檔的變數
复制代码
  1. :E_Exit
  2. endlocal&Set %1=%msg%
复制代码

TOP

回复 2# 77七
感謝指點,追蹤了下141行
  1. endlocal&set _msg=%msg%
复制代码
它似乎只會有空值

TOP

回复 3# aloha20200628
感謝指點,這個是我沒吸收到的,謝謝。

TOP

回复 4# newswan

感謝回覆,感覺他會是空值,實作也是空值.

TOP

用 for 获取输出
  1. pushd "%~dp0"
  2. for /f "usebackq tokens=1,* delims= " %%a in (` C2R-R2V-AIO.cmd `) do (
  3. if "%%a" == "msg" (set _msg_=%%b)
  4. )
  5. popd
复制代码
原文件 1481
  1. :E_Exit
  2. echo msg %msg%
复制代码

TOP

本帖最后由 77七 于 2024-6-9 13:09 编辑

回复 5# dreamer


  方法1将msg结果重定向到文本
140行左右添加行
  1. @echo off
  2. >>"%~dp0#.txt" echo,%msg%
  3. @exit /b
复制代码


1482行左右添加行
  1. :E_Exit
  2. >>"%~dp0#.txt" echo,%msg%
  3. if %_Debug% EQU 1 goto :eof
  4. echo.
  5. echo Press any key to exit.
复制代码


使用以下脚本调用
  1. @echo off
  2. cd /d "%~dp0"
  3. rem 把两个脚本放在同一目录下。或者自行修改两个脚本的 #.txt 路径
  4. del "%~dp0#.txt" 2>nul
  5. start "" "%~dp0C2R-R2V-AIO.cmd"
  6. :loop
  7. if not exist "%~dp0#.txt" (
  8. timeout 1
  9. goto :loop
  10. )
  11. set _msg=
  12. for /f "useback delims=" %%a in ("%~dp0#.txt") do (
  13. set _msg=%%a
  14. )
  15. if defined _msg (
  16. echo %_msg%
  17. ) else (
  18. echo 原脚本未定义msg
  19. )
  20. del "%~dp0#.txt" 2>nul
  21. pause
复制代码



方法2
可能需要将原脚本 36,41行两个start cmd.exe 及相关部分移植到调用脚本中,这样可以直接 call 调用,有点复杂

我是这样认为的,不知道对不对
bat小白,请多指教!谢谢!

TOP

回复 8# newswan
又學到一招了!真心感謝,這個方式可以取得C2R-R2V-AIO所有的輸出文字.感覺在這個基礎上,可以將所有需要的函數用Echo輸出而不用考慮setlocal造成的問題,太棒了!

TOP

回复 9# 77七
之前有測試寫入文件確實可行,想說寫入文件那干脆寫入到doskey 裡會不會更好一些.我的作法是在C2R-R2V-AIO 的:E_Exit後加上
  1. If "%msg%" EQU "Finished" Doskey Finished=%msg%
复制代码
然後在用findstr找出符合的字串,因為Finished是唯一條件,找到就成立找不到就失敗,所以用以下內容去判斷
  1. Doskey /macros|findstr /B /E /C:"finished=Finished">Nul&&Echo 完成
复制代码

TOP

回复 11# dreamer


  
  1. start %SystemRoot%\Sysnative\cmd.exe /c ""!_cmdf!" -wow "
复制代码
这行代码作用不是打开一个新窗口?打开的新窗口,call 已经获取不到其变量了吧
bat小白,请多指教!谢谢!

TOP

本帖最后由 77七 于 2024-6-9 14:51 编辑

回复 11# dreamer


   可以试着用以下脚本调用
脚本已经修改,刚才逻辑不对
  1. @echo off
  2. if exist "%SystemRoot%\Sysnative\cmd.exe" (
  3. call %SystemRoot%\Sysnative\cmd.exe /c "%~dp0C2R-R2V-AIO.cmd"
  4. ) else (
  5. if exist "%SystemRoot%\SysArm32\cmd.exe" (
  6. if /i %PROCESSOR_ARCHITECTURE%==AMD64 (
  7. call %SystemRoot%\SysArm32\cmd.exe /c "%~dp0C2R-R2V-AIO.cmd"
  8. ) else call "%~dp0C2R-R2V-AIO.cmd"
  9. ) else call "%~dp0C2R-R2V-AIO.cmd"
  10. )
  11. pause
复制代码



删除原脚本第25-43行,注意脚本中的路径,然后按照2楼方法。试试能不能取得msg值。(当然,2楼已经说明,msg存在空值可能)
本人认知、能力有限,可以试一下。
bat小白,请多指教!谢谢!

TOP

回复 12# 77七
33行有定義,它再次呼叫自身,所以應該還是可以取到值.
  1. set "_cmdf=%~f0"
复制代码

TOP

回复 14# dreamer


   
无论他执行哪个脚本,只要打开了新窗口,新窗口可以继承原窗口的变量,而不能回传。
可以简单写个脚本验证
  1. @echo off
  2. if "%~1" equ "" (
  3. title 旧
  4. set a=a
  5. start "" "%~f0" xx
  6. ) else (
  7. title 新
  8. set b=b
  9. )
  10. echo %a%
  11. echo %b%
  12. pause
复制代码
bat小白,请多指教!谢谢!

TOP

返回列表