J'ai écrit ce code pour obtenir un chemin de fichier (relatif):
$some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path {{PREVIOUS STDOUT}} -ChildPath "foo.json" | Get-Content {{PREVIOUS STDOUT}} | Convert-FromJson {{PREVIOUS STDOUT}} | {{PREVIOUS STDOUT}}.data
Ceci a généré l'erreur:
$this_directory = Get-ExecutingScriptDirectory $some_file_path = Join-Path -Path $this_directory -ChildPath "foo.json"
Cela indique à moi que la sortie de Get-ExecutingScriptDirectory est nulle - mais ce n'est pas le cas - quand j'écris le script comme ça, ça va:
Join-Path : Cannot bind argument to parameter 'Path' because it is null.
+ $some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path $_ -ChildPath "fo ...
+ ~~
+ CategoryInfo : InvalidData: (:) [Join-Path], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.JoinPathCommand
Le problème est donc que $ _ est nul. Je m'attendrais à ce que $ _ fasse référence à la sortie standard du tube précédent. La documentation MSDN le suggère également, mais il semble alors se contredire immédiatement:
$ _ contient l'objet courant dans l'objet pipeline. Vous pouvez utiliser cette variable dans les commandes qui exécutent une action sur chaque objet ou sur des objets sélectionnés dans un pipeline.
Dans le contexte de mon code, $ _ semble être qualifié d '"objet actuel dans l'objet pipeline" - mais je ne l'utilise pas avec une commande qui effectue une action sur chaque objet ou sur des objets sélectionnés dans un pipeline.
$$ et $ ^ semblaient prometteurs, mais la documentation MSDN dit juste quelques vagues ici sur les jetons lexicaux. La documentation sur $ PSItem était tout aussi concise.
Ce que j'aimerais aimerait faire, c'est créer un gros pipeline:
function Get-ExecutingScriptDirectory() {
return Split-Path $script:MyInvocation.MyCommand.Path # returns this script's directory
}
$some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path $_ -ChildPath "foo.json"
J'aimerais savoir où je me trompe à la fois sur le plan conceptuel et technique.
3 Réponses :
Utilisez simplement un bloc de code.
Get-Content (Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json")
La raison pour laquelle cela ne fonctionne pas dans ce code @ get-content est qu'il est évalué à faux.
function Get-ExecutingScriptDirectory() {
return Split-Path $script:MyInvocation.MyCommand.Path # returns this script's directory
}
if(Get-ExecutingScriptDirectory -eq $True){
write-host This is true
}
Output: This is true
Un objet ne peut être transmis en utilisant $ _ ou $ psItem que s'il est évalué à $ True.
Voici pourquoi cela fonctionne dans le premier exemple.
Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json" | Get-Content {$_} and Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json" | Get-Content $_
Vous pouvez également utiliser Parethesis pour isoler vos objets dans le pipeline.
exemple:
function Get-ExecutingScriptDirectory() {
return Split-Path $script:MyInvocation.MyCommand.Path # returns this script's directory
}
$some_file_path = Get-ExecutingScriptDirectory | Join-Path -Path {$_} -ChildPath "foo.json"
$some_file_path
read-host
Bien sûr, mais cela ne m'aide pas à mieux comprendre pourquoi $ _ fonctionne, mais uniquement dans un contexte de bloc de script. En outre, l'approche de bloc de script échoue avec les deux Get-ExecutingScriptDirectory | Join-Path -Path {$ _} -ChildPath "foo.json" | Get-Content {$ _} et Get-ExecutingScriptDirectory | Join-Path -Path {$ _} -ChildPath "foo.json" | Get-Content $ _ .
Vous pouvez faire ce que vous voulez en exécutant la commande ci-dessous:
"c:\temp" | Foreach-Object { $_ }
c:\temp
$filePath | Foreach-Object { $_ }
Path
----
c:\temp\test1\t.txt
$filePath | Foreach-Object { $_.Path }
c:\temp\test1\t.txt
Certaines commandes prennent en charge la liaison de paramètres de pipeline. Les options sont pipeline par valeur ou pipeline par propriété. Une bonne référence pour la liaison de paramètres est À propos des paramètres avancés des fonctions .
La recherche en ligne de la commande que vous allez utiliser donnera des informations sur la liaison des paramètres. Par exemple Join- Chemin , a une section de paramètres. Chaque paramètre aura une description comprenant le champ Accepter l'entrée du pipeline: . Pour qu'un paramètre accepte l'entrée de pipeline, il doit être True . Habituellement, il indiquera comment la valeur peut être transmise au pipeline ( ByPropertyName ou ByValue).
ByPropertyName indique que vous devez générer un objet contenant un nom de propriété correspondant au nom du paramètre. Ensuite, une fois que l'objet est acheminé, le paramètre se lie à la valeur du nom de propriété correspondant. Voir ci-dessous pour un exemple:
"c:\temp" | Join-Path -ChildPath "filepath" # c:\temp binds to `-Path` c:\temp\filepath
ByValue indique que toute valeur transmise tentera de se lier à ce paramètre. S'il existe des différences de type au moment de la liaison, une erreur sera probablement générée. Voir ci-dessous par exemple:
$filePath = [pscustomobject]@{Path = 'c:\temp\test1\t.txt'}
$filePath
Path
----
c:\temp\test1\t.txt
$filePath.Path # This binds to -Path in Get-Content
c:\temp\test1\t.txt
$filepath | Get-Content
Concernant $ _ , qui est synonyme de $ PSItem , est le objet d'entrée actuel dans un bloc de script. Vous le voyez généralement utilisé avec Foreach-Object et Where-Object . Si vous n'avez pas de bloc de script, vous ne pourrez pas utiliser $_ .
Vous pouvez techniquement tout diriger vers Foreach-Object code > ou Where-Object . Ensuite, l'objet de pipeline actuel sera représenté par $ _ . Vous n'avez pas besoin d'une collection car un seul élément peut être inséré. Voir ci-dessous:
(Get-Content -Path (Get-ExecutingScriptDirectory | Join-Path -ChildPath "foo.json" | ConvertFrom-Json)).data
Voici un exemple simple. Recherchez «accepter l'entrée du pipeline» dans la documentation. L'utilisation d'un scriptblock avec le paramètre -path de get-content est un peu avancé. La plupart des gens utilisent à la place un objet foreach. Cela fonctionne car -path accepte l'entrée de pipeline, mais uniquement par nom de propriété. Le paramètre -path de join-path peut être sur le tube par valeur, donc c'est plus facile. Cela vous sera très utile une fois que vous l'aurez compris. Il est peut-être plus facile d'essayer des choses parfois.
'.\' | Join-Path -ChildPath foo.json | foreach { Get-Content $_ } | ConvertFrom-Json
Ou avec foreach, qui est l'abréviation de foreach-object dans ce cas. Mais $ _ doit toujours être entre les accolades.
echo '"hi"' > foo.json
'.\' | Join-Path -ChildPath foo.json | Get-Content -Path { $_ } | ConvertFrom-Json
hi
si
Get-ExecutingScriptDirectoryrenvoie une valeur qui est un chemin, vous pouvez la diriger directement versJoin-Pathcar le paramètre-Pathaccepte la valeur par pipeline ->Get-ExecutingScriptDirectory | Join-Path -ChildPath .... Vous n'avez pas d'objet d'entrée courant$ _ici car vous n'utilisez pas de commande avec un bloc de script capable d'en traiter un. Si vous utilisezGet-ExecutingScriptDirectory | Foreach-Object {}, vous aurez accès à$ _dans le bloc de scriptForeachet pourrez créer d'autres variables à votre guise.@AdminOfThings
ForEach-Objectsemble bizarre ici car la fonction précédente (Get-ExecutingScriptDirectory) ne produit qu'une seule chose (une chaîne). Je ne sais pas si c'est techniquement un "objet de type chaîne". De plus, je veux diriger toute la sortie deGet-ExecutingScriptDirectoryvers un paramètre deJoin-Path, et je n'ai pas vu de variable automatique qui semblait appropriée.Déposez simplement
-Path $ _et cela fonctionnera.@AdminOfThings Oui, mais les deux
Get-ExecutingScriptDirectory | Join-Path -ChildPath "foo.json" | Get-Content $ _etGet-ExecutingScriptDirectory | Join-Path -ChildPath "foo.json" | Get-Contentne fonctionne pas. Je ne sais pas pourquoi la sortie standard du pipeline précédent est automatiquement acheminée vers le paramètre-Path(par opposition au paramètre -ChildPath, ou autre).En effet,
Get-Contentn'a pas de paramètre qui se lie par valeur à partir du pipeline. Vous devez soit diriger versForeach-Objectet utiliser-Path $ _, soit créer une propriété d'objet nomméePathavec votre chemin comme valeur avant rediriger versGet-Content.Utilisez simplement
(Get-Content -Path (Get-ExecutingScriptDirectory | Join-Path -ChildPath "foo.json" | ConvertFrom-Json)). Data. Je ne comprends pas l'exigence de tuyauterie. Il est plus simple d'utiliser simplement plus d'une ligne.@AdminOfThings Il n'y a aucune exigence de tuyauterie - la question était juste de faire avancer ma compréhension de la construction du langage. On dirait que vous dites que certaines fonctions ont des paramètres "adaptés aux tubes".
Join-Patha-Path,Get-Contentn'en a pas. Comment déterminez-vous généralement quelles fonctions ont des paramètres "pipe-friendly" dans l'écosystème Powershell? Actuellement, de mon point de vue, cela ressemble à des essais et des erreurs.Vous ne pouvez utiliser
$ _qu'à l'intérieur d'un scriptblock{}. C'est assez fondamental. C'est dans la documentation quels paramètres peuvent être redirigés, certains n'ont besoin que par valeur, d'autres par nom de propriété.@ js2010 Eh bien ... pas exactement. Voir docs.microsoft.com/en-us / powershell / module /… et docs.microsoft.com/en-us/powershell/module/… . Aucune distinction n'est faite au niveau de la partie paramètres de ces documents. Devez-vous à chaque fois explorer les exemples d'utilisation pour déterminer quels paramètres peuvent être acheminés?
Recherchez «accepter l'entrée du pipeline» dans ces documents.
@ js2010 Wow - yikes . Très bien, je suppose que cela répond à ma question. Merci.