Bir dosya yolunda ikiden fazla dizeyi birleştirmek için Birleştirme Yolu'nu nasıl kullanabilirim?


105

İki dizeyi bir dosya yolunda birleştirmek istersem, şu şekilde kullanırım Join-Path:

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

Bu yazdırır "C:\Program Files". Bunu ikiden fazla dizge için yapmak istersem:

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

PowerShell bir hata verir:

Join-Path: 'Microsoft Office' bağımsız değişkenini kabul eden bir konum parametresi bulunamıyor.
D: \ users \ ma \ my_script.ps1: 1 char: 18
+ $ yol = birleştirme yolu <<<< C: "Program Dosyaları" "Microsoft Office"
+ CategoryInfo: InvalidArgument: (:) [Join-Path] , ParameterBindingException
+
FullyQualifiedErrorId : PositionalParameterNotFound, Microsoft.PowerShell .Commands.JoinPathCommand

Bir dize dizisi kullanmayı denedim:

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

Ancak PowerShell benden çocuk yoluna girmemi istiyor ( -childpathbağımsız değişkeni belirtmediğim için ), örneğin "somepath" ve ardından üç dosya yolu oluşturuyor,

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

bu da doğru değil.

Yanıtlar:


171

.NET Path sınıfını kullanabilirsiniz :

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

3
Kesinlikle en özlü biçim ve yol ayırıcıları ve sondaki / baştaki eğik çizgileri yol parçalarında düzgün bir şekilde ele alır, ancak geçerli kabul edilen yanıt (temel dize birleştirme) bunu yapmaz.
David Keaveny

3
Yukarıdaki komutu powershell'imde çalıştırmak için şu hatayı alıyorum-"Combine" için bir aşırı yük bulamıyorum ve argüman sayısı: "3". Satırda: 1 karakter: 19 + [io.path] :: <<<< ('c: \', 'foo', 'bar') + CategoryInfo: NotSpecified: (:) [], MethodException + FullyQualifiedErrorId birleştirin: MethodCountCouldNotFindBest
Aamol

@Aamol Hangi CLR sürümünü çalıştırıyorsunuz ( $PSVersionTable)? Çalışıyor mu [io.path]::combine([string[]]('c:\','foo','bar'))?
Marek Toman

1
Görünüşe göre parametre sınırı 3, 3'ten sonra ilk parametre yok sayılır. (burada en azından ps 5.1, clr 4.0)
ehiller

4
@DavidKeaveny "yol ayırıcıları ve yol parçalarındaki son / baştaki eğik çizgileri düzgün bir şekilde işler" - Pek değil. join-pathbeklediğiniz şeyi yaparsa, join-path "C:\" "\foo"çıktılar C:\foo, Path.Combineancak ikinci bağımsız değişkenin baştaki bir ayırıcı içerdiğinde ilk bağımsız değişkeni yok sayar: [io.path]::combine('c:\', '\foo')sinir bozucu çıktılar \foo.
Quantic

99

Join-Path bir yol değeri ile donatılabildiğinden, birden çok Join-Path deyimini birlikte yönlendirebilirsiniz:

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

Muhtemelen olmasını istediğiniz kadar kısa değil, ancak tamamen PowerShell ve okunması nispeten kolay.


3
+1, tüm powershell 2,3,4'te çalışacağı için, [io.path] :: Combine API ile ilgili sorun, .net framework 3,4 için farklıdır
Ram

18

PowerShell 6.0 beri bir sahiptir Yol-Üyelik yeni bir parametre olarak adlandırılan -AdditionalChildPathve edebilirsiniz bir yol dışı-box birden kısımlarını birleştirmek . Ya ekstra parametre sağlayarak ya da sadece bir eleman listesi sağlayarak.

Belgelerden örnek :

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

Yani PowerShell 6.0 ve varyantınızın üstünde

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

beklendiği gibi çalışıyor!


17

Join-Path tam olarak aradığınız şey değil. Birden çok kullanımı vardır, ancak aradığınız kullanım değildir. Join-Path ile Partying'den bir örnek :

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

Bir dizi dizeyi kabul ettiğini ve alt dizeyi her biri tam yollar oluşturacak şekilde birleştirdiğini görüyorsunuz. Örneğinizde $path = join-path C: "Program Files" "Microsoft Office". Üç konumsal argüman ilettiğiniz ve join-pathyalnızca ikisini kabul ettiğiniz için hatayı alıyorsunuz . Aradığınız şey a -joinve bunun bir yanlış anlaşılma olduğunu görebiliyordum. Bunun yerine örneğinizle şunu düşünün:

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

-Joinöğe dizisini alır ve bunları \tek bir dizede birleştirir .

C:\Program Files\Microsoft Office

Küçük bir kurtarma girişimi

Evet, bu cevabın daha iyi olduğuna katılıyorum , ancak benimki yine de işe yarayabilir. Yorumlar, eğik çizgilerle ilgili bir sorun olabileceğini gösteriyor, bu nedenle birleştirme yaklaşımıma devam etmek için bunu da yapabilirsiniz.

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

Bu nedenle, fazladan eğik çizgi ile ilgili sorunlar varsa, dizenin başında olmadıkları sürece ele alınabilir ( UNC yollarına izin verir ). [io.path]::combine('c:\', 'foo', '\bar\')beklendiği gibi çalışmazdı ve benimki bunu hesaba katardı. Tüm senaryoları hesaba katamayacağınız için her ikisi de girdi için uygun dizeler gerektirir. Her iki yaklaşımı da düşünün, ama evet, diğer yüksek puanlı cevap daha kısa ve varlığından bile haberdar değildim.

Ayrıca, belirtmek isterim ki, cevabım, temel sorunu ele almak için bir öneri sunmanın yanı sıra, OP'nin yaptığı şeyin ne kadar yanlış olduğunu açıklıyor.


2
Bu yanlıştır, çünkü birden çok ardışık yolda \ işe yarayacak olsa da, çirkin ve potansiyel olarak sorunlara neden olabilir.
Mikhail Orlov

@MikhailOrlov Olası bir sorunu, olabileceğini düşünerek tanımlayabilir misiniz? Başka bir önerin var mı? Bir sorun görmediğim için soruyorum. Bir sorun varsa onu ele almak isterim.
Matt

2
Son zamanlarda çok sayıda düşük kaliteli kodla çalışıyorum, insanlar yolları String.Equals ile karşılaştırıyor ve yolları String.Split ('\\') ile boş dizeleri kaldırmadan ayrıştırıyor. Sonuç olarak daha tehlikeli bir şey düşünemiyorum, çoğunlukla sadece paranoyak oluyorum. Düzenlemeniz için teşekkürler.
Mikhail Orlov

3
Yol ayırıcının açık bir şekilde dahil edilmesi, platformlar arası taşınabilirlikle ilgili sorunlara neden olabilir. PowerShell şu anda yalnızca Windows üzerinde çalışsa da, bu çok uzak olmayan bir gelecekte büyük olasılıkla değişecektir ve iyi alışkanlıkları olabildiğince erken geliştirmek iyi bir fikirdir. Bu alışkanlıkların diğer dillere geçebileceğinden bahsetmiyorum bile.
bshacklett

10

Hala .NET 2.0 kullanıyorsanız, ikiden fazla parçayı birleştirmek için ihtiyaç duyduğunuz aşırı yüklemeye [IO.Path]::Combinesahip olmayacaksınız params string[]ve "Birleştirme" için bir aşırı yük bulunamıyor hatasını ve sayı sayısı: "3" göreceksiniz .

Biraz daha az zarif, ancak saf bir PowerShell çözümü, yol parçalarını manuel olarak toplamaktır:

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

veya

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

5

İşte ChildPath için bir dize dizisi kullanırken istediğinizi yapacak bir şey.

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

Hangi çıktılar

C:\Program Files\Microsoft Office

Bulduğum tek uyarı, $ yol için başlangıç ​​değerinin bir değere sahip olması gerektiğidir (boş veya değer atanmamış olamaz).


4

Burada, rastgele sayıda bileşeni bir yola birleştirmek için saf bir PowerShell işlevi yazmanın iki yolu daha var.

Bu ilk işlev, tüm bileşenleri depolamak için tek bir dizi ve ardından bunları birleştirmek için bir foreach döngüsü kullanır:

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
}

Yol bileşenleri bir dizideki öğeler olduğundan ve tümü tek bir bağımsız değişkenin parçası olduğundan, virgülle ayrılması gerekir. Kullanım şekli aşağıdaki gibidir:

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


Bu işlevi yazmanın daha minimalist bir yolu, yerleşik $argsdeğişkeni kullanmak ve ardından foreach döngüsünü Mike Fair'in yöntemini kullanarak tek bir satıra daraltmaktır.

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

İşlevin önceki sürümünden farklı olarak, her yol bileşeni ayrı bir bağımsız değişkendir, bu nedenle bağımsız değişkenleri ayırmak için yalnızca bir boşluk gerekir:

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

2

Aşağıdaki yaklaşım, birleştirme Yolu deyimlerinden daha özlüdür:

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

$ p daha sonra birleştirilmiş 'a \ b \ c \ d' yolunu tutar.

(Bunun Mike Fair'inki ile aynı yaklaşım olduğunu fark ettim, üzgünüm.)


1

Ya da onun için kendi işlevinizi yazabilirsiniz (bunu yapmaya son verdim).

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

Daha sonra işlevi şu şekilde çağırabilirsiniz:

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

Bu, .NET Framework'e bağlı değil, normal Join-Path işleviyle aynı davranışa sahip olma avantajına sahiptir.


0

Bunu şu şekilde kullanabilirsiniz:

$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"
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.