如何使用join-path将两个以上的字符串组合到文件路径中?

时间:2014-09-16 23:45:24

标签: powershell

如果我想将两个字符串合并到一个文件路径中,我会像这样使用join-path

$path = join-path C: "Program Files"
write-host $path

打印"C:\Program Files"。如果我想为两个以上的字符串执行此操作:

$path = join-path C: "Program Files" "Microsoft Office"
write-host $path

Powershell引发错误:

Join-Path : A positional parameter cannot be found that accepts argument 'Micro
soft Office'.
At D:\users\ma\my_script.ps1:1 char:18
+ $path = join-path <<<<  C: "Program Files" "Microsoft Office"
    + CategoryInfo          : InvalidArgument: (:) [Join-Path], ParameterBindi
   ngException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell
   .Commands.JoinPathCommand

我尝试使用字符串数组:

[string[]] $pieces = "C:", "Program Files", "Microsoft Office"
$path = join-path $pieces
write-host $path

但是Powershell提示我输入子路径(因为我没有指定-childpath参数),例如&#34; somepath&#34;,然后创建三个文件路径,

C:\somepath
Program Files\somepath
Microsoft Office\somepath

也不对。

10 个答案:

答案 0 :(得分:137)

您可以使用.NET Path类:

[IO.Path]::Combine('C:\', 'Foo', 'Bar')

答案 1 :(得分:77)

由于Join-Path可以通过管道传递其路径值,因此您可以将多个Join-Path语句组合在一起:

Join-Path "C:" -ChildPath "Windows" | Join-Path -ChildPath "system32" | Join-Path -ChildPath "drivers"

它并不像你希望的那样简洁,但它完全是PowerShell并且相对容易阅读

答案 2 :(得分:15)

Join-Path并不是您想要的。它有多种用途,但不是您正在寻找的用途。来自Partying with Join-Path

的示例
Join-Path C:\hello,d:\goodbye,e:\hola,f:\adios world
C:\hello\world
d:\goodbye\world
e:\hola\world
f:\adios\world

您会看到它接受一个字符串数组,并将子字符串连接到每个字符串创建完整路径。在您的示例$path = join-path C: "Program Files" "Microsoft Office"中。您收到错误,因为您传递了3个位置参数,join-path只接受2.您要找的是-join,我可以看出这是一个误解。请考虑使用您的示例:

"C:","Program Files","Microsoft Office" -join "\"

-Join获取项目数组,并将它们与\连接成一个字符串。

C:\Program Files\Microsoft Office

轻微尝试打捞

是的,我会同意this answer更好但我的仍然有效。评论表明可能存在斜杠问题,所以为了保持我的连接方法你也可以这样做。

"C:","\\Program Files\","Microsoft Office\" -join "\" -replace "(?!^\\)\\{2,}","\"

因此,如果存在额外斜杠的问题,只要它们不在字符串的开头(允许UNC路径),就可以处理它。 [io.path]::combine('c:\', 'foo', '\bar\')无法按预期工作,我的将会解释这一点。两者都需要适当的字符串输入,因为您无法考虑所有方案。考虑两种方法,但是其他更高评价的答案更简洁,我甚至不知道它存在。

另外,我想回答一下,我的回答解释了OP在提出解决核心问题的建议的基础上做错了什么。

答案 3 :(得分:7)

如果您仍在使用.Net 2.0,那么[IO.Path]::Combine将不会有params string[]重载,您需要加入两个以上的部分,并且您将看到错误无法找到超载for“Combine”和参数count:“3”。

稍微不那么优雅但纯粹的Powershell解决方案是手动聚合路径部分:

join-path C: (join-path "Program Files" "Microsoft Office")

join-path (join-path C: "Program Files") "Microsoft Office"

答案 4 :(得分:5)

自PowerShell 6.0起,Join-Path具有名为-AdditionalChildPath新参数,并且可以现成地组合路径的多个部分。通过提供额外的参数或仅提供元素列表即可。

来自the documentation的示例:

Join-Path a b c d e f g
a\b\c\d\e\f\g

因此在PowerShell 6.0及更高版本中

$path = Join-Path C: "Program Files" "Microsoft Office"

按预期工作!

答案 5 :(得分:4)

在为ChildPath使用字符串数组时,这些内容可以满足您的需求。

$path = "C:"
@( "Program Files", "Microsoft Office" ) | %{ $path = Join-Path $path $_ }
Write-Host $path

哪个输出

C:\Program Files\Microsoft Office

我发现唯一的警告是$ path的初始值必须有一个值(不能为null或为空)。

答案 6 :(得分:1)

或者你可以为它编写自己的函数(这就是我最终要做的)。

function Join-Path-Recursively($PathParts) {
    $NumberOfPathParts = $PathParts.Length;

    if ($NumberOfPathParts -eq 0) {
        return $null
    } elseif ($NumberOfPathParts -eq 1) {
        return $PathParts[0]
    } else {
        return Join-Path -Path $PathParts[0] -ChildPath $(Join-Path-Recursively -PathParts $PathParts[1..($NumberOfPathParts-1)])
    }
}

然后你可以这样调用这个函数:

Join-Path-Recursively -PathParts  @("C:", "Program Files", "Microsoft Office")
Join-Path-Recursively  @("C:", "Program Files", "Microsoft Office")

这样做的好处是具有与普通Join-Path功能完全相同的行为,而不依赖于.NET Framework。

答案 7 :(得分:1)

还有另外两种方法可以编写纯Powershell函数,以将任意数量的组件连接到路径中。

第一个函数使用单个数组存储所有组件,然后使用foreach循环将它们组合在一起:

function Join-Paths {
    Param(
        [Parameter(mandatory)]
        [String[]]
        $Paths
    )
    $output = $Paths[0]
    foreach($path in $Paths[1..$Paths.Count]) {
        $output = Join-Path $output -ChildPath $path
    }
    $output
}

由于路径成分是数组中的元素,并且是单个参数的所有部分,因此必须用逗号分隔。用法如下:

PS C:\> Join-Paths 'C:', 'Program Files', 'Microsoft Office'
C:\Program Files\Microsoft Office


编写此函数的一种更简单的方法是使用内置的$ args变量,然后使用Mike Fair的方法将foreach循环折叠为一行。

function Join-Paths2 {
    $path = $args[0]
    $args[1..$args.Count] | %{ $path = Join-Path $path $_ }
    $path
}

与该函数的先前版本不同,每个路径组件都是一个单独的参数,因此仅需一个空格即可分隔参数:

PS C:\> Join-Paths2 'C:' 'Program Files' 'Microsoft Office'
C:\Program Files\Microsoft Office

答案 8 :(得分:0)

你可以这样使用它:

$root = 'C:'
$folder1 = 'Program Files (x86)'
$folder2 = 'Microsoft.NET'

if (-Not(Test-Path $(Join-Path $root -ChildPath $folder1 | Join-Path -ChildPath $folder2)))
{
   "Folder does not exist"
}
else 
{
   "Folder exist"
}

答案 9 :(得分:0)

以下方法怎么样,比传递Join-Path语句更简洁:

$p="a"; "b","c","d" | Foreach-Object -Process { $p = Join-Path $p $_ }

$ p然后保存连接的路径'a \ b \ c \ d'。

编辑:刚刚注意到,这与Mike Fair的方法完全相同,