我想获取.ps1文件中特定函数的最后一行。我已经用powershell v3代码完成了这个:
function GetEndLineNumber($ParseFile, $functionName))
{
$AbstractSyntaxTree = $NewParser::ParseFile($ParseFile, [ref]$null, [ref]$null)
$functionsInFile = $AbstractSyntaxTree.FindAll({$args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst]}, $true)
#endregion
$initializeFunction = $null
foreach($function in $functionsInFile)
{
if($function.Name -eq $functionName)
{
$initializeFunction = $function
break
}
}
if($initializeFunction -eq $null){ return 0 }
$initializeFunctionBody = $initializeFunction.Body
return $initializeFunctionBody.Extent.EndLineNumber
}
但是这个脚本也应该在v2上运行,我尝试使用System.Management.Language.PSParser和ScriptBlock。但没有任何成功。有人知道如何在.ps1文件中获取特定函数名的最后一行(作为int或字符串)?
我认为这里有一些误解: 我想在.ps1脚本中获取特定函数的最后一行。不是函数中特定函数的最后一行。因为我必须在最后将自己的代码添加到此函数中 这是一个简单的示例,我的脚本可以看起来如何:
1function test321
2 {
3 Write-Host "test3142"
4 }
5
6function test1
7{
8 if($true)
9 {
10 Write-Host "hello"
11 }
12 #comment
13
14 Write-host "end"
15
16}
17
18function test2
19{
20 #bla
21}
我想要一个名为的函数,例如像GetEndLineNumber($ scriptFile,$ functionName),它应该像这样工作:
$path = "C:\Scripts\test.ps1"
$lastLine = GetEndLineNumber $path "test1"
$lastLine should be in this case 15 or 16.
答案 0 :(得分:5)
在PowerShell V2中,我们可以使用System.Management.Automation.PSParser
并执行一些操作
使用生成的标记解析自己:
function GetEndLineNumber {
param(
$scriptFile,
$functionName
)
$code = Get-Content -LiteralPath $scriptFile
$tokens = [System.Management.Automation.PSParser]::Tokenize($code, [ref]$null)
$waitForFuncName = $false
$funcFound = $false
$level = 0
foreach($t in $tokens) {
switch($t.Type) {
Keyword {
if ($t.Content -eq 'function') {
$waitForFuncName = $true
}
}
CommandArgument {
if ($waitForFuncName) {
$waitForFuncName = $false
$funcFound = $t.Content -eq $functionName
}
}
GroupStart {
++$level
}
GroupEnd {
--$level
if ($funcFound -and $level -eq 0 -and $t.Content -eq '}') {
return $t.StartLine
}
}
}
}
}
我没有彻底测试它,但我尝试了一些函数和脚本 返回正确的行号。
答案 1 :(得分:1)
在V3中,对于已存在的函数还有另一个更简单的选项:
$cmd = Get-Command -Name $functionName -CommandType Function,Filter
if ($null -ne $cmd)
{
return $cmd.ScriptBlock.Ast.Extent.EndLineNumber
}
这适用于使用function / filter关键字以及Set-Item定义的函数,例如
Set-Item -Path function:foo -Value { return 42 }
使用Parser api的原始代码在这种情况下无法正常工作。
在V2中,PSParser api可能是最好的选择 - 但它需要一些稍微棘手的解析。找到'功能后#39;您可以跳过可选参数列表(匹配'('和')')然后您将匹配' {&# 39;和'}'令牌,最后一个没有出现的'}'令牌是你的最后一行。
这不是一个复杂的代码,但它有点棘手,例如如果你没有跳过可选参数列表,你可能会错误地找到匹配的花括号作为默认参数,例如
function foo($a = {}) {}
答案 2 :(得分:0)
这种获取最后一行的方式如何:
首先。输出PS1文件:
. .\Myscript.ps1
然后获取函数的scriptblock:
$myFunction = Get-Item Function:\MyFunction
($myFunction.ScriptBlock ).ToString().split("`n") | select -last 1
正如你可以在@mjolinor的回答中看到的那样,你应该对这种分裂感到骄傲。
答案 3 :(得分:0)
添加到@ JPBlanc的答案,小心那个分裂。它似乎计算花括号之间的所有内容作为脚本块的一部分,包括紧接在之前和之后的任何换行:
function test {
'line1'
'line2'
'line3'
}
$myFunction = Get-Item Function:\test
($myFunction.ScriptBlock ).ToString().split("`n").count
5
function test {'line1'
'line2'
'line3'}
$myFunction = Get-Item Function:\test
($myFunction.ScriptBlock ).ToString().split("`n").count
3
从第一个元素中取出分割的最后一个元素将返回一个空行。
为了安全起见,我会在你进行拆分之前通过.trim()运行它。你也可以使用$function:<function name>
代替Get-Item
来缩短它,并使用数组切片代替-Select
:
function test {
'line1'
'line2'
'line3'
}
$function:test.tostring().trim().split("`n")[-1]
'line3'