Ответ 1
Вы можете использовать .NET путь класс:
[IO.Path]::Combine('C:\', 'Foo', 'Bar')
Если я хочу объединить две строки в путь к файлу, я использую 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
что тоже не правильно.
Вы можете использовать .NET путь класс:
[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"
. Вы получаете ошибку, поскольку передаете три позиционных аргумента, а 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\')
не будет работать, как ожидалось, и мой ответит за это. Оба требуют правильных строк для ввода, поскольку вы не можете учитывать все сценарии. Рассмотрим оба подхода, но да, другой более высокий рейтинг является более кратким, и я даже не знал, что он существует.
Кроме того, я хотел бы отметить, что мой ответ объясняет, как то, что делает ОП, было неправильным, помимо предложения о решении основной проблемы.
Начиная с 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"
работает как положено!
Если вы все еще используете .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"
Здесь что-то будет делать то, что вы хотите, когда используете массив строк для ChildPath.
$path = "C:"
@( "Program Files", "Microsoft Office" ) | %{ $path = Join-Path $path $_ }
Write-Host $path
Какие выходы
C:\Program Files\Microsoft Office
Единственное предостережение, которое я обнаружил, это то, что начальное значение для $path должно иметь значение (не может быть пустым или пустым).
Или вы могли бы написать свою собственную функцию для этого (что я и сделал в итоге).
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.
Вот еще два способа написания чистой функции 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
Вы можете использовать это так:
$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"
}
Следующий подход более лаконичен, чем использование операторов Join-Path:
$p = "a"; "b", "c", "d" | ForEach-Object -Process { $p = Join-Path $p $_ }
$ p затем содержит объединенный путь 'a\b\c\d'.
(Я только заметил, что это тот же подход, что и у Майка Фэйра, извините.)
если целью является создание новой папки, это может помочь:
$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;
}