[PowerShell]鬼擋牆之呼叫function回傳多個值
前言
雖然知道PowerShell跟.NET的設計方式完全不一樣,但今天還是被一個小地方卡了好幾個小時,這邊分享一下莫名其妙的慘痛經驗給大家笑一下。
案例
功能需求:將某一段資訊記成log,寫在某個路徑底下。當路徑不存在時,要建立對應的資料夾。
簡單到爆的需求吧,我們把程式列出來:
function Logging
{
param ($logFile, $logInfo)
$logInfo >> $logFile
}
#資料夾不存在,就建立
function CheckFolderExist($path)
{
if ((Test-Path $path) -eq $false)
{
mkdir $path
}
}
#取得Log檔路徑與檔名
function GetLogFileName
{
# log file
$todayStr = Get-Date -format "yyyyMMdd"
$logPath = "\\127.0.0.1\c$\temp\"
CheckFolderExist $logPath
$logFile = $logPath + "Joey-" + $todayStr + ".log"
return $logFile
}
Logging (GetLogFileName)"test by Joey"
我們把『檢查資料夾,建立資料夾』抽成一個function,使用mkdir來建立資料夾。
這樣的程式碼看起來很合情合理吧?實際跑一次,我們來看結果:
為什麼我的路徑變成『\\127.0.0.1\c$\temp\127.0.0.1\c$\temp\Joey-20110629.log』了?見鬼了…
檢查一下結果,資料夾有被明確的建立起來,那就是寫檔的問題囉?再執行一次發現,檔案成功寫進去了。
為什麼第二次執行就可以寫進去?看來原因是在建立資料夾,但是資料夾也有被成功建立啊,就這樣鬼擋牆了。
用偵錯模式下去跑跑看:
logFile的值的確就是我們要的:\\127.0.0.1\c$\temp\Joey-20110629.log
但錯誤資訊還是一樣:Could not find a part of the path '\\127.0.0.1\c$\temp\127.0.0.1\c$\temp\Joey-20110629.log'.
折騰了好一陣子,換個寫法檢查,才發現GetLogFileName這個function回來的東西,跟想像的完全不一樣。
拆牆
我們先將GetLogFileName回傳值放到$result裡面,接著進行偵錯。
- function中return的$logFile仍然是:
但是$result呢?
見鬼了!為什麼$result是array,把$logPath跟$logFile一起回傳了?? - 找了老半天後發現,$result的結果:{\\127.0.0.1\c$\temp, \\127.0.0.1\c$\temp\Joey-20110629.log}
第一個element並不是想像中在GetLogFileName function裡面的$logPath變數,而是CheckFolderExist這個function裡面的回傳值。(天啊!mkdir $path竟然會回傳$path的值) - 更機車的是,我並沒有宣告變數去接CheckFolderExist這個function回傳的東西。讓我更納悶的是,啊我不是在GetLogFileName最後一行,寫著『return $logFile』嗎?為什麼兩個都回來了…
就是這麼機車的過程中,找到兇手了。
- CheckFolderExist的function中,呼叫了mkdir的function,會回傳$path。沒有用變數接就代表會回傳回去。
- GetLogFileName的function中,呼叫了CheckFolderExist,也沒有用變數去接,所以代表GetLogFileName最後也會回傳$path。但function還沒結束,所以會繼續往下跑。
- GetLogFileName的function中,最後return了$logFile,加上剛剛CheckFolderExist回傳的$path,所以最後就回傳了{$path, $logFile}
知道原因之後,我們修改一下程式:
宣告一個$path來接CheckFolderExist的回傳值,然後就不管它。
執行結果正確無誤。
結論
PowerShell果然跟一般的.NET完全不一樣啊…呼叫function記得要用變數去接,不然會回傳一個array。相對的,如果需要回傳多個值,也可以透過這樣的方式去接。
把我的青春還來啊…真的是書到用時方恨少啊 >”<
blog 與課程更新內容,請前往新站位置:http://tdd.best/