Join-Pathを使用して3つ以上の文字列をファイルパスに結合するにはどうすればよいですか?


105

2つの文字列をファイルパスに結合する場合は、次のJoin-Pathように使用します。

$path = Join-Path C: "Program Files"
Write-Host $path

それは印刷し"C:\Program Files"ます。2つ以上の文字列に対してこれを実行したい場合:

$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」などの子パスを入力するように求め、次に3つのファイルパスを作成します。

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

どちらでもありません。

回答:


171

.NET Pathクラスを使用できます。

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

3
確かに最も簡潔な形式であり、パスフラグメントのパスセパレーターと末尾/先頭のスラッシュを適切に処理しますが、現在受け入れられている回答(基本的な文字列の連結)はこれを行いません。
David Keaveny、2015

3
私のpowershell iseで上記のコマンドを実行すると、このエラーが発生します-"Combine"のオーバーロードと引数の数: "3"が見つかりません。1行目:char:19 + [io.path] :: combine <<<<( 'c:\'、 'foo'、 'bar')+ CategoryInfo:NotSpecified:(:) []、MethodException + FullyQualifiedErrorId: MethodCountCouldNotFindBest
Aamol

@Aamol実行しているCLRのバージョン($PSVersionTable)DOESの[io.path]::combine([string[]]('c:\','foo','bar'))作品?
Marek Toman 2016

1
パラメータの制限は3のようです。3の後、最初のパラメータは無視されます。(ここでは、少なくともps 5.1、clr 4.0)
ehiller '19年

4
@DavidKeaveny "パスセパレーターとパスフラグメントの末尾/先頭のスラッシュを適切に処理します"-実際にはそうではありません。join-path期待どおりのjoin-path "C:\" "\foo"出力をC:\foo行いますが、Path.Combine2番目の引数に先行セパレータが含まれている場合は常に最初の引数を無視し[io.path]::combine('c:\', '\foo')ます\foo
クォンティック

99

Join-Pathはパス値をパイプ処理できるため、複数のJoin-Pathステートメントを一緒にパイプ処理できます。

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

思ったほど簡潔ではありませんが、完全にPowerShellであり、比較的読みやすいです。


3
+1はすべてのpowershell 2,3,4で機能するため、[io.path] :: Combine APIの問題は.netフレームワークの場合とは異なります3,4
Ram

18

PowerShellの6.0以来、参加パスがあり、新たなパラメータと呼ばれるに-AdditionalChildPathしてすることができますすぐにパスの複数の部品を組み合わせました。追加のパラメーターを提供するか、要素のリストを指定するだけです。

ドキュメントの例:

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"

期待どおりに動作します!


17

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"。3つの位置引数を渡し、join-path2つしか受け入れないため、エラーが発生します。あなたが探しているのはであり-join、これは誤解であることがわかりました。代わりにあなたの例でこれを考えてください:

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

-Joinアイテムの配列を受け取り、それらを\単一の文字列に連結します。

C:\Program Files\Microsoft Office

サルベージの小さな試み

はい、私はこの答えがより良いことに同意しますが、私のものはまだ働くことができます。コメントはスラッシュに問題がある可能性があることを示唆しているので、私の連結アプローチを維持するためにこれを行うこともできます。

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

したがって、余分なスラッシュに問題がある場合は、文字列の先頭にない限り処理できます(UNCパスを許可します)。[io.path]::combine('c:\', 'foo', '\bar\')期待どおりに動作せず、私がそれを説明します。すべてのシナリオを説明できるわけではないため、どちらも入力に適切な文字列が必要です。両方のアプローチを検討してください。しかし、はい、他のより高い評価の回答はより簡潔であり、それが存在することさえ知りませんでした。

また、指摘したいのですが、私の答えは、コア問題に対処するための提案を提供することに加えて、OPの動作がどのように間違っていたかを説明しています。


2
パス内の連続する複数の\は機能するが、醜く、潜在的に問題を引き起こす可能性があるため、これは誤りです。
ミハイルオルロフ2015年

@MikhailOrlov発生する可能性を示唆するだけの潜在的な問題について説明できますか?別の提案がありますか?問題はないと思います。何か問題があれば、対処したいと思います。
Matt

2
私は最近多くの低品質のコードを扱ってきました。人々はString.Equalsでパスを比較し、空の文字列を削除せずにString.Split( '\\')でパスを解析します。結果としてこれ以上危険なものを考えることはできません。ほとんど私は偏執的です。編集ありがとうございます。
ミハイルオルロフ2015年

3
パス区切り文字を明示的に含めると、クロスプラットフォームの移植性で問題が発生する可能性があります。PowerShellは現在Windows上でのみ動作しますが、それほど遠くない将来に変更される可能性が高いため、できるだけ早い段階で適切な習慣を身に付けることをお勧めします。これらの習慣が他の言語に移ることは言うまでもありません。
bshacklett 2015年

10

引き続き.NET 2.0を使用している場合、3つ以上のパーツを結合する必要[IO.Path]::Combineがあるparams string[]オーバーロードは発生せず、「Combine」のオーバーロードが見つからないというエラーと引数の数:「3」が表示されます。

少しエレガントではありませんが、純粋なPowerShellソリューションはパス部分を手動で集約することです:

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

または

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

5

ChildPathに文字列配列を使用するときに必要なことを行うものを次に示します。

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

どの出力

C:\Program Files\Microsoft Office

私が見つけた唯一の警告は、$ pathの初期値には値が必要である(nullまたは空にすることはできない)ことです。


4

次に、任意の数のコンポーネントをパスに結合する純粋なPowerShell関数を作成する2つの方法を示します。

この最初の関数は、単一の配列を使用してすべてのコンポーネントを格納し、次に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:\>結合パス 'C:'、 'Program Files'、 'Microsoft Office'
C:\ Program Files \ Microsoft Office


この関数を作成するよりミニマリストな方法は、組み込み$args変数を使用してから、Mike Fairのメソッドを使用してforeachループを1行に折りたたむことです。

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

2

次のアプローチは、Join-Pathステートメントのパイプ処理よりも簡潔です。

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

$ pは、連結されたパス 'a \ b \ c \ d'を保持します。

(申し訳ありませんが、これはMike Fairのアプローチとまったく同じです。)


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")

これには、.NET Frameworkに依存せずに、通常のJoin-Path関数とまったく同じ動作をするという利点があります。


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"
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.