如何在PowerShell中使几个命令在它们自己的作用域中运行?



假设我正在做一些基本的字符串操作,如下所示:

$segments = $PathToExe -split "\"
$last = $segments[$segments.Length - 1]
$ProcName = ($last -split ".")[0]

这一小段代码的目的是获取& name"可执行文件路径的一部分,稍后将其传递给Get-Process-Name参数。

在脚本中逐字逐句地编写这个命令序列非常简单,但是它使临时变量$segments$last泄漏到脚本的作用域中。当以后引入类似的变量名时,这可能会导致意想不到的结果,或者更糟糕的是,更有可能的是,错误地传达了变量的意图。显然,在语义上和功能上将这些变量限制到它们正在执行的特定任务将提高脚本的可维护性。

有不同的方法来实现这种行为:

  • 将代码包装成函数
    function NameFromExePath([string] $Path)
    {
    $segments = $Path -split "\"
    $last = $segments[$segments.Length - 1]
    return ($last -split ".")[0]
    }
    
    如果你太频繁地这样做,它会有点笨重,会降低可读性,通常情况下,函数代码只在脚本中使用一次,就在函数本身之后。
  • 使用脚本块:
    $Name = icm {
    $segments = $PathToExe -split "\"
    $last = $segments[$segments.Length - 1]
    return ($last -split ".")[0]
    }
    
    这给icm带来了一些开销,感觉有点像黑客。icm的作用与它平时的作用大不相同。
  • 删除变量:
    # Piece of code from beginning of the question goes here
    # <...>
    rv segments
    rv last
    
    这是相当庞大的,大小与要删除的变量数量线性扩展,并且是手动的(因此容易出错)。

在这三种方法中(希望还有一种我不知道的更好的方法),哪一种是最习惯的?或者,像这样避免可变污染的做法从一开始就不常见吗?

我相信scriptblock是创建新作用域最惯用的方式。只需将Invoke-Command(别名icm)替换为调用操作符&,以减少开销:

$PathToExe = 'c:footest.exe'
$Name = & {
$segments = $PathToExe -split "\"
$last = $segments[$segments.Length - 1]
($last -split ".")[0]  # Implicit output
}
$Name
$segments
$last

输出:

test

同样,当任何(隐式)输出被捕获到分配的变量中时,您可以删除return语句。


您甚至可以使用scriptblock向管道输出一些内容:

& {
foreach( $i in 1..10 ) { $i }
} | Write-Host -ForegroundColor Green

…或者将内容管道到scriptblock中的:

1..10 | & {
process { $_ * 2 }
} | Write-Host -ForegroundColor Green

这缩小了语句和命令之间的差距,因为语句通常不能用作管道的一部分。

最新更新