我有以下两个脚本:
### main.ps1
. .\inner.ps1 $args[0] $myInvocation.MyCommand.Definition
echo "second call"
Write-Host -NoNewLine "Press any key to continue..."
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
和
### inner.ps1
if( $($args[0]) -ne "secondRun") {
echo "first"
echo $($args[1])
& $($args[1]) "secondRun"
exit
}
exit
中的inner.ps1
命令未从调用者脚本main.ps1
退出,因此我点击了第二次调用代码的两倍。
我也可以退出来电吗?
我怎样才能获得正确的递归?
我想将inner.ps1
中的所有/大部分递归负担放在尽可能干净的main.ps1
中,这意味着避免在main.ps1
中添加如下行:
if( $($args[0]) -ne "secondRun") {exit;}
答案 0 :(得分:2)
即使使用点源(.
),脚本也无法指示其来电者到exit
,因此在您当前的设置中,您需要某些条件main.ps1
,检查. .\inner.ps1
来电后是否需要退出。
鉴于辅助脚本inner.ps1
是点源的,因此可以修改调用者的环境main.ps1
,人们想知道为什么递归是完全必要的。
然而,这个答案的其余部分接受了问题的前提。
功能
OP自己提出a solution that encapsulates the recursive-invocation details inside inner.ps1
,但问题是使用成功流(常规输出流)发送控制信息 - $TRUE
或{{ 1}} - 表示检查该信息($FALSE
)的if
语句消耗 if (. .\inner.ps1) ...
的常规输出,因此抑制它。 [1]
换句话说:该方法仅在main1.ps1
碰巧根本不产生输出时才有效,或者调用者不关心main.ps1
输出。
解决方案是将控制流基于退出代码 (PowerShell在自动变量main.ps1
中反映):
$LASTEXITCODE
和
### inner.ps1
if(-not $__inner_already_recursed) {
'inner: reinvoking main...'
$__inner_already_recursed=$true # set flag to indicate that recursion has happened
. $myInvocation.ScriptName # re-invoke main.ps1
exit 0 # Signal need to continue execution with $LASTEXITCODE 0
} else {
'inner: not reinvoking...'
exit 1 # Signal that this is already the 2nd invocation.
}
正如OP所述,用于维护### main.ps1
'main: entering'
# Call the helper script that performs the recursive invocation.
. .\inner.ps1
if ($LASTEXITCODE -eq 1) { exit } # 1 means previously already reinvoked -> exit
# We only get here once, in the recursive invocation.
'main: should only get here once'
中的递归调用状态的辅助变量不能预先存在(或者至少不具有真值),因此其名称 - inner.ps1
- 是选择将风险降至最低。
[1] $__inner_already_recursed
电话不受影响,因为它们直接打印到控制台,但它们的输出既不能被捕获也不能通过管道发送。
(通过额外的努力,你可以在PSv5 +中,但这通常是不明智的,在这里没有帮助。)
答案 1 :(得分:-1)
这种方法对来电者来说似乎很轻松。
### inner.ps1
if( -not $recurseScript ) {
write-host "first"
write-host $myInvocation.ScriptName
$recurseScript=$TRUE
& $myInvocation.ScriptName
return $TRUE
}
$recurseScript=$FALSE
return $FALSE
要使main.ps1
递归,现在我只需要行if(. .\inner.ps1) {exit}
:
### main.ps1
if(. .\inner.ps1) {exit}
Write-Host "second";
Write-Host -NoNewLine "Press any key to continue...";
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown");
当然,在运行$recurseScript
之前,定义的变量$TRUE
和main.ps1
不应该存在。