Как использовать 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
что тоже неправильно.
10 ответов:
поскольку 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