Si je veux combiner deux chaînes dans un chemin de fichier, j'utilise join-path
comme ceci:
$path = join-path C: "Program Files"
write-Host $path
Cela imprime "C:\Program Files"
. Si je veux faire cela pour plus de deux chaînes cependant:
$path = join-path C: "Program Files" "Microsoft Office"
write-Host $path
Powershell génère une erreur:
Join-Path : A positional parameter cannot be found that accepts argument 'Micro
soft Office'.
At D:\users\ma\my_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
J'ai essayé d'utiliser un tableau de chaînes:
[string[]] $pieces = "C:", "Program Files", "Microsoft Office"
$path = join-path $pieces
write-Host $path
mais Powershell me demande d'entrer le childpath (puisque je n'ai pas spécifié l'argument -childpath
), par exemple "somepath", puis crée trois chemins de fichiers,
C:\somepath
Program Files\somepath
Microsoft Office\somepath
ce qui n'est pas juste non plus.
Vous pouvez utiliser la classe .NET Path:
[io.path]::combine('c:\', 'foo', 'bar')
Comme Join-Path peut utiliser sa valeur de chemin, vous pouvez diriger simultanément plusieurs instructions Join-Path:
Join-Path "C:" -ChildPath "Windows" | Join-Path -ChildPath "system32" | Join-Path -ChildPath "drivers"
Ce n'est pas aussi concis que vous le souhaiteriez probablement, mais c'est entièrement PowerShell et relativement facile à lire.
Join-Path n'est pas exactement ce que vous recherchez. Il a des usages multiples mais pas celui que vous recherchez. Un exemple de Partying with 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
Vous voyez qu'il accepte un tableau de chaînes et concatène la chaîne enfant à chaque création de chemins complets. Dans votre exemple $path = join-path C: "Program Files" "Microsoft Office"
. Vous obtenez l'erreur puisque vous passez 3 arguments de position et que join-path
n'en accepte que 2. Ce que vous recherchez est un -join
et je pourrais voir cela comme un malentendu. Considérez plutôt ceci avec votre exemple:
"C:","Program Files","Microsoft Office" -join "\"
-Join
prend le tableau d'éléments et les concatène avec \
en une seule chaîne.
C:\Program Files\Microsoft Office
Tentative mineure de sauvetage
Oui, je conviens que cette réponse est meilleure, mais la mienne pourrait toujours fonctionner. Les commentaires suggèrent qu'il pourrait y avoir un problème avec les barres obliques. Par conséquent, pour rester dans mon approche de concaténation, vous pouvez le faire également.
"C:","\\Program Files\","Microsoft Office\" -join "\" -replace "(?!^\\)\\{2,}","\"
Donc, s'il y a des problèmes avec des barres obliques supplémentaires, elles peuvent être traitées tant qu'elles ne sont pas au début de la chaîne (autorise les chemins UNC). [io.path]::combine('c:\', 'foo', '\bar\')
ne fonctionnerait pas comme prévu et le mien en tiendrait compte. Les deux nécessitent des chaînes appropriées pour l'entrée car vous ne pouvez pas prendre en compte tous les scénarios. Considérez les deux approches, mais oui, l'autre réponse la mieux notée est plus concise et je ne savais même pas qu'elle existait.
En outre, j'aimerais préciser que ma réponse explique comment le PO a mal agi en plus de suggérer de résoudre le problème fondamental.
Si vous utilisez toujours .Net 2.0, [IO.Path]::Combine
n'aura pas de surcharge params string[]
, vous devez joindre plus de deux parties et vous verrez l'erreur Impossible de trouver une surcharge pour "Combine" et le nombre d'arguments: "3" .
La solution Powershell légèrement moins élégante mais pure consiste à agréger manuellement les éléments de chemin:
join-path C: (join-path "Program Files" "Microsoft Office")
ou
join-path (join-path C: "Program Files") "Microsoft Office"
Voici quelque chose qui fera ce que vous voudriez en utilisant un tableau de chaînes pour ChildPath.
$path = "C:"
@( "Program Files", "Microsoft Office" ) | %{ $path = Join-Path $path $_ }
Write-Host $path
Quelles sorties
C:\Program Files\Microsoft Office
Le seul inconvénient que j'ai trouvé est que la valeur initiale de $ path doit avoir une valeur (ne peut pas être nulle ou vide).
Ou vous pouvez écrire votre propre fonction (ce que j'ai fini par faire).
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)])
}
}
Vous pouvez alors appeler la fonction comme ceci:
Join-Path-Recursively -PathParts @("C:", "Program Files", "Microsoft Office")
Join-Path-Recursively @("C:", "Program Files", "Microsoft Office")
Cela présente l’avantage d’avoir exactement le même comportement que la fonction de chemin de jointure normale et de ne pas dépendre du .NET Framework.
Depuis PowerShell 6.0, Join-Path a un nouveau paramètre appelé -AdditionalChildPath
et peut combiner plusieurs parties d’un chemin d’origine. Soit en fournissant le paramètre supplémentaire, soit en fournissant simplement une liste d'éléments.
Exemple tiré de la documentation :
Join-Path a b c d e f g
a\b\c\d\e\f\g
Donc, dans PowerShell 6.0 et supérieur, votre variante
$path = Join-Path C: "Program Files" "Microsoft Office"
fonctionne comme prévu!
Vous pouvez l'utiliser de cette façon:
$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"
}
Voici deux autres manières d'écrire une fonction pure PowerShell pour joindre un nombre arbitraire de composants dans un chemin.
Cette première fonction utilise un seul tableau pour stocker tous les composants, puis une boucle foreach pour les combiner:
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
}
Étant donné que les composants de chemin d'accès sont des éléments d'un tableau et qu'ils font tous partie d'un seul argument, ils doivent être séparés par des virgules. L'utilisation est la suivante:
PS C: \> chemins d'accès 'C:', 'Program Files', 'Microsoft Office' C:\Program Files\Microsoft Office
Une méthode plus minimaliste pour écrire cette fonction consiste à utiliser la variable intégrée $ args, puis à réduire la boucle foreach en une seule ligne à l'aide de la méthode de Mike Fair.
function Join-Paths2 {
$path = $args[0]
$args[1..$args.Count] | %{ $path = Join-Path $path $_ }
$path
}
Contrairement à la version précédente de la fonction, chaque composant de chemin est un argument séparé. Par conséquent, seul un espace est nécessaire pour séparer les arguments:
PS C: \> Join-Paths2 'C:' 'Program Files' '' Microsoft Office ' C:\Program Files\Microsoft Office
Que diriez-vous de l'approche suivante, elle est plus concise que les instructions de jointure de chemin d'accès Join:
$p="a"; "b","c","d" | Foreach-Object -Process { $p = Join-Path $p $_ }
$ p contient alors le chemin concaténé 'a\b\c\d'.
Edit: je viens de remarquer que c'est exactement la même approche que celle de Mike Fair, désolée.