
我正在嘗試製作一個程式來選擇文件名,然後將其通過管道傳輸到變數中。
我的嘗試:
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
使用後會發出
myVar:1.14.4
計劃是讓它進入並回顯命令,所以我這樣做了
@echo off
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
echo e %myVar%
cmd /k
但所發生的一切是
e
我究竟做錯了什麼?另外,有沒有辦法用 FOR 來做到這一點?
答案1
我究竟做錯了什麼?
很簡單 - 您正在嘗試使用無法工作的技術;-) 由於 Windows 管道的工作方式,因此不可能使用管道命令輸出在父環境中設定環境變數。
您的腳本正在命令進程中運行 - 我們稱之為父進程。
Windows 管道啟動兩個子命令進程,每個進程都有自己獨立的環境空間。管道的左側在第一個子級中執行,右側在第二個子級中執行。管道將第一個子級的輸出作為第二個子級的輸入發送。成功SET /P
在子進程中定義了新的 myVar 變量,並且SET MYVAR
命令顯示該值。偉大的。
但隨後管道結束,兩個子進程都終止,它們關聯的環境消失。無法將 myVar 環境值從子管道程序傳回父環境。
Windows 管道設計有許多令人驚訝的副作用,讓那些不完全理解其機制的人感到困惑。看https://stackoverflow.com/q/8192318/1012053了解更多。我建議閱讀問題和所有答案。
有沒有辦法用 FOR 做到這一點?
是的,在環境變數中捕捉命令輸出的正確方法是透過 FOR,特別FOR /F
是 DavidPostill 所示。雖然他的程式碼有一個確定的問題,一個潛在的問題,一個低效率的地方。
USEBACKQ
處理命令的輸出時不需要使用。使用常規單引號'
比反引號更簡單:for /f %%F in ('yourCommand') do ...
錯誤是echo myVar:%myVar%
在 FOR 迴圈體內使用了 。這將顯示運行循環之前存在的值,myVar
因為解析該行時會發生百分比擴展,並且整個 FOR 循環將一步解析。您需要啟用延遲擴充 ( setlocal enableDelayedExpansion
),然後使用echo !myVar!
檢視循環內設定的值。
可能會出現另一個問題 - FOR /F 會將值解析為空格分隔的標記,並且僅捕獲第一個標記。如果檔案名稱包含空格,則除非使用 DELIMS 選項指定無分隔符,否則您將無法取得完整名稱。
for /f "delims=" %%F in (....) do ....
但沒有必要使用DIR /B
and FOR /F
。您可以簡單地使用普通FOR
循環而不使用該/F
選項。
例如,以下將簡單列出所有文件:
for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF
指定~nx
僅使用檔案名稱和副檔名,放棄磁碟機和資料夾路徑。
通常不需要使用環境變數 - 只需%%F
在迴圈中使用 FOR 變數即可完成工作。
但是如果因為某些原因你確實需要循環之外的值,你當然可以這樣做
for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do set "myVar=%%~nxF"
但這只會捕獲迭代的最後一個檔案。 myVar 變數將在每次迭代時被覆蓋。您的原始設計將捕獲列出的第一個文件(假設它可以工作)。除非您知道 Van1 資料夾僅包含一個文件,否則這似乎都不是一個好主意。
如果您需要將所有檔案捕獲到變數中,那麼您需要使用偽數組。 Batch 沒有正式的陣列概念,但可以輕鬆模擬。如果您只需在網上搜尋“批次檔數組”,您就可以找到大量範例