Как использовать 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 : A positional parameter cannot be found that accepts argument 'Micro
soft Office'.
At D:usersmamy_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 аргумент), например "somepath", а затем создает три пути к файлам,



C:somepath
Program Filessomepath
Microsoft Officesomepath


что тоже неправильно.

617   10  

10 ответов:

вы можете использовать класс .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". Вы получаете ошибку, так как вы передаете 3 позиционных аргумента и join-path только 2. То, что вы ищете-это -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, было неправильно поверх предложения по решению основной проблемы.

если вы все еще используете .Net 2.0, то [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"

вот то, что будет делать то, что вы хотите при использовании строкового массива для дочернего пути.

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

выходы

C:\Program Files\Microsoft Office

единственное предостережение, которое я нашел, заключается в том, что начальное значение для $path должно иметь значение (не может быть пустым или пустым).

вы можете использовать его таким образом:

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

или вы могли бы написать свою собственную функцию для этого (что я делал).

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.

Как насчет следующего подхода, он более лаконичен, чем операторы Соединения трубопроводов:

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

$p тогда содержит сцепленный путь 'a\b\c\d'.

Edit: просто заметил, что это тот же самый подход, что и Майк фейр, извините.

вот еще два способа написать чистую функцию 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, а затем свернуть цикл 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

если объект создать новую папку, это может помочь:

$folder = 'C:\test\Microsoft Office';
$newfolder = '/Test Folder\'
$newfolder = $newfolder.Trim("\/");
echo $newfolder;

if (Test-Path "$folder$newfolder" ) 
{
 echo "Path already exists: $folder$newfolder"
 Remove-Item -path $folder$newfolder;
}
Else
{
 $folder = New-Item -type directory -path $folder  -name $newfolder;
 $folderpath = $folder.FullName;
 echo $folderpath;
}

Comments

    Ничего не найдено.