Подтвердить что ты не робот

Как использовать 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 & lt; & lt; & lt; & lt; C: "Программные файлы" "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

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

4b9b3361

Ответ 1

Вы можете использовать .NET путь класс:

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

Ответ 2

Поскольку Join-Path можно передать значение пути, вы можете передать несколько операторов Join-Path вместе:

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

Это не так кратко, как вы, вероятно, хотели бы, но это полностью PowerShell и относительно легко читается.

Ответ 3

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,}","\"

Поэтому, если есть проблемы с дополнительными слешами, их можно обработать, если они не находятся в начале строки (допускаются пути UNC). [io.path]::combine('c:\', 'foo', '\bar\') не будет работать, как ожидалось, и мой ответит за это. Оба требуют правильных строк для ввода, поскольку вы не можете учитывать все сценарии. Рассмотрим оба подхода, но да, другой более высокий рейтинг является более кратким, и я даже не знал, что он существует.

Кроме того, я хотел бы отметить, что мой ответ объясняет, как то, что делает ОП, было неправильным, помимо предложения о решении основной проблемы.

Ответ 4

Начиная с PowerShell 6.0, Join-Path имеет новый параметр с именем -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"

работает как положено!

Ответ 5

Если вы все еще используете .NET 2.0, то у [IO.Path]::Combine не будет перегрузки params string[], которая необходима для объединения более двух частей, и вы увидите ошибку. Не удается найти перегрузку для "Объединить" и аргумента количество: "3".

Немного менее элегантно, но чистое решение PowerShell состоит в том, чтобы вручную объединять части пути:

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

или

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

Ответ 6

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

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

Какие выходы

C:\Program Files\Microsoft Office

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

Ответ 7

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

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.

Ответ 8

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

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

Ответ 9

Вы можете использовать это так:

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

Ответ 10

Следующий подход более лаконичен, чем использование операторов Join-Path:

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

$ p затем содержит объединенный путь 'a\b\c\d'.

(Я только заметил, что это тот же подход, что и у Майка Фэйра, извините.)

Ответ 11

если целью является создание новой папки, это может помочь:

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