Comment passer des paramètres à une fonction?

11

J'ai besoin de traiter une copie de travail SVN dans un script PS, mais j'ai du mal à passer des arguments aux fonctions. Voici ce que j'ai:

function foo($arg1, $arg2)
{
  echo $arg1
  echo $arg2.FullName
}

echo "0: $($args[0])"
echo "1: $($args[1])"
$items = get-childitem $args[1] 
$items | foreach-object -process {foo $args[0] $_}

Je veux passer $arg[0]comme $arg1à foo, et $arg[1]que $arg2. Cependant, cela ne fonctionne pas, pour une raison quelconque, il $arg1est toujours vide:

PS C:\Users\sbi> .\test.ps1 blah .\Dropbox
0: blah
1: .\Dropbox
C:\Users\sbi\Dropbox\Photos
C:\Users\sbi\Dropbox\Public
C:\Users\sbi\Dropbox\sbi
PS C:\Users\sbi>

Remarque: Le "blah"paramètre n'est pas transmis en tant que $arg1.

Je suis absolument sûr que c'est quelque chose de hilarante simple (je viens juste de commencer à faire du PS et je me sens toujours très maladroit), mais je me suis cogné la tête contre cela depuis plus d'une heure maintenant, et je ne trouve rien.

sbi
la source

Réponses:

2

Le $arg[]tableau semble perdre la portée à l'intérieur de ForEach-Object .

function foo($arg1, $arg2)
{
  echo $arg1
  echo $arg2.FullName
}

echo "0: $($args[0])"
echo "1: $($args[1])"
$zero = $args[0]
$one = $args[1]
$items = get-childitem $args[1] 
$items | foreach-object {
    echo "inner 0: $($zero)"
    echo "inner 1: $($one)"
}
Justin Dearing
la source
Je pourrais accepter n'importe laquelle des trois réponses que j'ai obtenues jusqu'à présent, mais je vais choisir celle-ci, car cela montre ce que j'ai fini par faire.
sbi
10

La raison pour laquelle $ args [0] ne renvoie rien dans foreach-object est que $ args est une variable automatique qui prend des paramètres sans nom et sans correspondance dans une commande et foreach-object est une nouvelle commande. Il n'y a aucun paramètre inégalé pour le bloc de processus, donc $ args [0] est nul.

Une chose qui peut vous aider est que vos scripts peuvent avoir des paramètres, tout comme les fonctions.

param ($SomeText, $SomePath)
function foo($arg1, $arg2)
{
  echo $arg1
  echo $arg2.FullName
}

echo "0: $SomeText"
echo "1: $SomePath"
$items = get-childitem $SomePath
$items | foreach-object -process {foo $SomeText $_}

Alors que vous commencez à vouloir plus de fonctionnalités de vos paramètres, vous voudrez peut-être consulter un article de blog que j'ai écrit sur la progression des paramètres de $ args vers les paramètres avancés actuels que nous pouvons utiliser maintenant.

Steven Murawski
la source
Blabla. Des raisons comme celle-ci expliquent pourquoi j'évite les incorporations comme Foreach-Object en faveur de l'utilisation de la bonne construction en boucle foreach brute.
Trevor Sullivan
Ah ok. C'est ce que je comprends maintenant. Merde, cela semble assez contre-intuitif, cependant!
sbi
3

Essayez quelque chose comme ceci:

# Use an advanced function
function foo
{
  [CmdletBinding()]
  param (
      [string] $arg1
    , [string] $arg2
  )

  Write-Host -Object $arg1;
  Write-Host -Object $arg2;
}

# Create array of "args" to emulate passing them in from command line.
$args = @('blah', 'c:\test');

echo "0: $($args[0])"
echo "1: $($args[1])"

# Force items to be returned as an array, in case there's only 1 item returned
$items = @(Get-ChildItem -Path $args[1]);
Write-Host -Object "There are $($items.Count) in `$items";

# Iterate over items found in directory
foreach ($item in $items) {
    foo -Arg1 $args[0] -Arg2 $item.FullName
}
Trevor Sullivan
la source
Que "forcer les éléments à être retournés sous forme de tableau" est quelque chose que je devrais en effet ajouter. Merci pour l'astuce!
sbi
Ouais, je dois faire attention si vous ne récupérez qu'un seul élément - en le castant explicitement comme un tableau, vous obtenez des résultats cohérents, vous pouvez donc itérer dessus en utilisant foreach.
Trevor Sullivan