program tip

Join-Path를 사용하여 두 개 이상의 문자열을 파일 경로로 결합하는 방법은 무엇입니까?

radiobox 2020. 8. 26. 07:45
반응형

Join-Path를 사용하여 두 개 이상의 문자열을 파일 경로로 결합하는 방법은 무엇입니까?


두 문자열을 파일 경로로 결합하려면 다음 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 : 'Microsoft Office'인수를 허용하는 위치 매개 변수를 찾을 수 없습니다.
D : \ users \ ma \ my_script.ps1 : 1 char : 18
+ $ path = join-path <<<< C : "Program Files" "Microsoft Office"
+ CategoryInfo : InvalidArgument : (:) [Join-Path] , ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound, Microsoft.PowerShell
.Commands.JoinPathCommand

문자열 배열을 사용해 보았습니다.

[string[]] $pieces = "C:", "Program Files", "Microsoft Office"
$path = Join-Path $pieces
Write-Host $path

그러나 PowerShell은 -childpath"somepath"와 같은 자식 경로 ( 인수를 지정하지 않았으므로)를 입력하라는 메시지를 표시 한 다음 세 개의 파일 경로를 만듭니다.

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

어느 쪽도 옳지 않습니다.


.NET Path 클래스를 사용할 수 있습니다 .

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

Join-Path는 경로 값으로 파이프 될 수 있으므로 여러 Join-Path 문을 함께 파이프 할 수 있습니다.

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

원하는만큼 간결하지는 않지만 완전히 PowerShell이며 비교적 읽기 쉽습니다.


Join-Path는 정확히 당신이 찾고있는 것이 아닙니다. 여러 용도가 있지만 찾고있는 용도는 아닙니다. 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". 세 개의 위치 인수를 전달하고 join-path두 개만 허용 하므로 오류가 발생합니다 . 당신이 찾고있는 것은이며 -join, 이것이 오해임을 알 수 있습니다. 대신 귀하의 예에서 이것을 고려하십시오.

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

-Join항목의 배열을 가져 와서 \단일 문자열로 연결합니다 .

C:\Program Files\Microsoft Office

인양을위한 사소한 시도

예, 이 답변 이 더 낫다 는 데 동의 하지만 여전히 작동 할 수 있습니다. 주석은 슬래시에 문제가있을 수 있음을 암시하므로 내 연결 방식을 유지하려면이 작업도 수행 할 수 있습니다.

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

So if there are issues with extra slashes it could be handled as long as they are not in the beginning of the string (allows UNC paths). [io.path]::combine('c:\', 'foo', '\bar\') would not work as expected and mine would account for that. Both require proper strings for input as you cannot account for all scenarios. Consider both approaches, but, yes, the other higher-rated answer is more terse, and I didn't even know it existed.

Also, would like to point out, my answer explains how what the OP doing was wrong on top of providing a suggestion to address the core problem.


Since PowerShell 6.0, Join-Path has a new parameter called -AdditionalChildPath and can combine multiple parts of a path out-of-the-box. Either by providing the extra parameter or by just supplying a list of elements.

Example from the documentation:

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

So in PowerShell 6.0 and above your variant

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

works as expected!


If you are still using .NET 2.0, then [IO.Path]::Combine won't have the params string[] overload which you need to join more than two parts, and you'll see the error Cannot find an overload for "Combine" and the argument count: "3".

Slightly less elegant, but a pure PowerShell solution is to manually aggregate path parts:

Join-Path C: (Join-Path  "Program Files" "Microsoft Office")

or

Join-Path  (Join-Path  C: "Program Files") "Microsoft Office"

Here's something that will do what you'd want when using a string array for the ChildPath.

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

Which outputs

C:\Program Files\Microsoft Office

The only caveat I found is that the initial value for $path must have a value (cannot be null or empty).


Or you could write your own function for it (which is what I ended up doing).

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)])
    }
}

You could then call the function like this:

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

This has the advantage of having the exact same behaviour as the normal Join-Path function and not depending on the .NET Framework.


Here are two more ways to write a pure PowerShell function to join an arbitrary number of components into a path.

This first function uses a single array to store all of the components and then a foreach loop to combine them:

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
}

Because the path components are elements in an array and all part of a single argument, they must be separated by commas. Usage is as follows:

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


A more minimalist way to write this function is to use the built-in $args variable, and then collapse the foreach loop into a single line using Mike Fair's method.

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

Unlike the previous version of the function, each path component is a separate argument, so only a space is necessary to separate the arguments:

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

You can use it this way:

$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"
}

The following approach is more concise than piping Join-Path statements:

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

$p then holds the concatenated path 'a\b\c\d'.

(I just noticed that this is the exact same approach as Mike Fair's, sorry.)

참고URL : https://stackoverflow.com/questions/25880122/how-do-i-use-join-path-to-combine-more-than-two-strings-into-a-file-path

반응형