在PowerShell中拆分,选择,加入

本文关键字:选择 加入 拆分 PowerShell | 更新日期: 2023-09-27 18:31:59

PowerShell中的以下C#(伪)代码的等效项是什么?

string str = "abc def ghi";
str = str.Split(" ").Select(s => "'"" + MakeRootedPath(s) + "'"").Join(" ");
// Result:
str == @"""C:'root'abc"" ""C:'root'def"" ""C:'root'ghi""";

它在空格处拆分字符串,转换每个标记并将其放入引号中,然后将标记与空格重新组合。

我在想这样的事情:

$str = $str -Split " " | Select-Object "`"" + (MakeRootedPath $_) + "`"" | -Join " "

但这主要是由我到处发现的碎片组成的,我很确定它不会像这样工作。我知道我可以用.NET的方式做,写很多行[string].Join等等,但我正在寻找一个优雅的PowerShell解决方案。我知道它存在,但学习语法很复杂。

PS:这是完整性的MakeRootedPath函数。

# Returns a rooted path. Non-rooted paths are interpreted relative to $rootDir.
#
function MakeRootedPath($path)
{
    if (![System.IO.Path]::IsPathRooted($path))
    {
        return "$rootDir'$path"
    }
    return $path
}

在PowerShell中拆分,选择,加入

String.Split() 方法可以像在 C# 中一样使用:

PS> $str = "abc def ghi"
PS> $str.Split(" ")
abc
def
ghi

Select()Join()扩展方法不可用,但你可以使用 PowerShell 特定的ForEach()方法和-join运算符:

$str.Split(" ").ForEach({"""$(MakeRootedPath $_)"""}) -join " "

PowerShell 4.0 中引入了ForEach()扩展方法 - 在旧版本中,必须使用 foreach(){} 循环:

(foreach($s in $str.Split(" ")){"""$(MakeRootedPath $_)"""}) -join " "

或管道连接到ForEach-Object cmdlet:

($str.Split(" ")|ForEach-Object{"""$(MakeRootedPath $_)"""}) -join " "
# Suppose you have MakeRootedPath somewhere that does something usefull
# I provide a stub here so it is runnable in a console
function MakeRootedpath {"C:'$args"}
# option 1, use foreach-object
('abc def ghi' -split ' ' | foreach-object { "`"$(MakeRootedPath $_ )`""}) -join ' '
# option 2, use select-object (two times, as you need to expand property)
('abc def ghi' -split ' ' | select-object @{N='Item';E={"`"$(MakeRootedPath $_ )`" "}} | 
Select -ExpandProperty Item) -join ' '

如果你MakeRootedPath()所做的只是返回一个绝对路径,请使用带有适当参数的Join-Path。这样

$s = "abc def ghi"
$r = "c:'root"
$o = $s -split " " | % { join-path $r $_ }
# Check output for single result
$o[1]
c:'root'def
# Print the whole array
$o
c:'root'abc
c:'root'def
c:'root'ghi

至于添加的逻辑,让我们使用 .Net 方法来检查绝对路径。例如,可以使用正则表达式来测试输入。既然已经有库方法,为什么还要费心重新发明轮子呢?

function RootedPath($s, $rootPath) {
    if(-not [System.IO.Path]::IsPathRooted($s)) { 
        return join-path $rootPath $s 
    } else { return $s } 
}
$s = "abc d:'def ghi" # NB: 2nd value is absolute path
$o = $s -split ' ' | % { RootedPath $_ "c:'myRoot" }
# Let's generate a fancy output
$p = '"' + $($o -join '" "') + '"'
$p # print output
"c:'myRoot'abc" "d:'def" "c:'myRoot'ghi"