Слишком много результатов после выполнения сценария powershell с циклами foreach - PullRequest
0 голосов
/ 28 сентября 2019

Я только начинаю свое путешествие с Powershell и выполняю некоторые базовые сценарии, начиная с foreach и, если конструкции elseif.

У меня проблема с циклами foreach.

Я пытался написать простой код с параметром, заданным пользователем.У меня есть файл CSV с 2 столбцами: Zenskie (женщина) и Meskie (мужчина), заполненные именами.Мой код состоит в том, чтобы найти имя, данное пользователем в CSV, и в качестве выходной информации дать информацию о поле.

Часть файла CSV:

Zenskie;Meskie
Ada;Aaron
Adamina;Abdon
Adela;Abel
Adelajda;Abelard
Adriana;Abraham
Adrianna;Achilles
Agata;Adam
Agnieszka;Adelard
Aida;Adnan
Bogna;Dawid

Я также добавил небольшой поворот для своей жены - должен быть специальный комментарий только для ее имени, и здесь у меня есть проблема.Результат такой, каким он должен быть, но он показывается несколько раз (я думаю, столько же строк в CSV).

Я также попытался добавить часть «else» в конце, если вводданное пользователем не присутствовало в списке.Но когда я это сделал, это дает результаты предыдущего "elseif".

Я пытался использовать другой elseif с "elseif ($ UserName -ne $ Man), но это также дает мне неправильный ответ.

Могу поспорить, что здесь что-то упущено ...


Param (
  [string]$UserName = (Read-Host " Tell me your name ")
)

$Names = Import-Csv -Path C:\Powershell\Moje_nowe\Lista_imion3.csv -Delimiter ";"

ForEach ($item in $Names) {
  $Women = $item.("Zenskie")
  $Man = $item.("Meskie")
  if ($UserName -eq $Women) {
    Write-Output "$UserName you are women!"
  }
  elseif ($UserName -eq $Man) {
    Write-Output "$UserName you are man!"
  }
  elseif ($UserName -eq "Bogna") {
    Write-Output "Kiss me!! :)"
  }
  else {
    Write-Output "$UserName you have an odd name"
  }
}

Ожидаемый результат:

для ввода Богна:

Tell me your name: bogna

Kiss me!! :)

Фактический результат:

Kiss me!! :)

Kiss me!! :)

Kiss me!! :)

ит. д.

Когда я добавляю деталь, когда вход отсутствует в списке:

Ожидается:

Tell me your name: bdsdsd


bdsdsd you have an odd name

Фактически:

независимо от того, чтоЯ поставил в качестве ввода

bdsdsd you have an odd name

bdsdsd you have an odd name

bdsdsd you have an odd name

и т. Д.

Ответы [ 3 ]

1 голос
/ 28 сентября 2019

Результат такой, каким он должен быть, но он показан несколько раз (я думаю, столько же строк в CSV).

Действительно: учитывая, что вы зациклилисьДля объектов, импортируемых из строк CSV по отдельности, оператор if оценивается для каждого .

. Используйте break для выхода из цикла, когда вы нашли совпадение вif и elseif ответвляются , чтобы исправить это (но не в else ветви, потому что он потенциально должен ждать, пока все объекты будут проверены, чтобы сделать вывод, что совпадение не былонайдено).

Предостережение : Используйте break только в foreach цикле (утверждение) (как в вашем вопросе), а не в конвейер с командлетом ForEach-Object (как в принятом ответе ).В последнем случае break ищет вмещающий цикл в стеке вызовов, и если он не находит ни одного, завершает сценарий целиком .
Короче: Используйте только когда-либо break и continue в циклах (foreach, while, ...) или switch операторов ;break и continue совершенно не связаны с конвейерами (но вы можете использовать return в блоке сценария ForEach-Object для перехода к входному объекту конвейера next ).

Начиная с PowerShell v7, прямой поддержки выхода из (10) * конвейера по требованию нет;добавление такой поддержки запрашивается в этом выпуске GitHub .

Однако намного проще и эффективнее воспользоваться -in Оператор PowerShell, оператор проверки членства в массиве (сдерживание) (PSv3 +; в PSv2 или, альтернативно, используйте -contains, где порядок операнда обращен), который позволяет вам выполнить single тест (для каждого значения сравнения) по всем строкам CSV , как также показано в полезный ответ Олафа .

Упрощенный пример:

Примечание: Приведенный ниже код сначала считывает все данные CSV в память, а затем создает из нее два массива для значений в двух столбцах.Для файла со списком имен это не должно быть проблемой памяти;однако при работе с большими наборами входных данных вам может потребоваться решение, которое обрабатывает входной файл CSV строка за строкой в ​​конвейере.

# Parse sample CSV input into objects with .Zenskie and .Meskie properties.
$names = @'
Zenskie;Meskie
Ada;Aaron
Adamina;Abdon
Adela;Abel
'@ | ConvertFrom-Csv -Delimiter ';'

# Extract the male and female names into individual arrays.
# Note how no quoting is needed to acces the properties (columns) by names
# and how accessing a property on the input array ($names) automatically
# returns the property values *from all array elements*, a feature known
# as member enumeration.
$maleNames = $names.Meskie
$femaleNames = $names.Zenskie

# Test a few sample names.
'Abdon', 'Bogna', 'Adela', 'Bill' | ForEach-Object {

  if ($_ -eq 'Bogna') { # exception
    "Pocałuj mnie!! :)"
  }
  elseif ($_ -in $maleNames) { # -in tests presence in the array, case-insensitively
    "$_, you are a man."
  }
  elseif ($_ -in $femaleNames) {    
    "$_, you are a woman."
  }
  else {
    "$_, you have an odd name."
  }

}

Выше приведено:

Abdon, you have are a man.
Pocałuj mnie!! :)
Adela, you have are a woman.
Bill, you have an odd name.
1 голос
/ 28 сентября 2019

Вы можете использовать цикл «до ... до», чтобы игра продолжалась ...; -)

$CSV = @'
Zenskie;Meskie
Ada;Aaron
Adamina;Abdon
Adela;Abel
Adelajda;Abelard
Adriana;Abraham
Adrianna;Achilles
Agata;Adam
Agnieszka;Adelard
Aida;Adnan
Bogna;Dawid
'@ | ConvertFrom-Csv -Delimiter ';'

do {
    $UserName = Read-Host " Tell me your name (End with 'quit')" 
    if ($UserName -eq 'Bogna') { "Kiss me!! :)" }
    elseif ($UserName -in $CSV.Zenskie) { "$UserName you are woman!" }
    elseif ($UserName -in $CSV.Meskie) { "$UserName you are man!" }
    else  { "$UserName you have an odd name" }
} until ($Username -eq 'quit')
0 голосов
/ 28 сентября 2019

попробуйте это:

Param ([string]$UserName = (Read-Host " Tell me your name " ))

#if Bogna, not necessary to loop, print and out
if ($UserName -eq "Bogna")
{
   "Kiss me!! :)  (nice declaration)"
   return
}

#loop on all elements and if you found as you want, break for not continue ==> attention break leave the programm in pipe foreach
$FirstElement=Import-csv -Path "C:\Powershell\Moje_nowe\Lista_imion3.csv" -Delimiter ";" | %{

    if ($_.Zenskie -eq $UserName)
    {
        "$UserName you are women!"

        break
    }
    elseif ($_.Meskie -eq $UserName)
    {
        "$UserName you are man!"

        break
    }

}

# BE CAREFULL IF BREAK IS RAISED THE SCRIPT IS ENDED AND THIS CODE DOESNT EXECUTED
if (! $FirstElement)
{
"$UserName you have an odd name, Brrrrr !"
}

Если ваш сценарий продолжится после цикла csv, не оставляйте сценарий с разрывом, вы можете сделать это:

Param ([string]$UserName = (Read-Host " Tell me your name " ))

#if Bogna, not necessary to loop, print and out
if ($UserName -eq "Bogna")
{
   "Kiss me!! :)  (nice declaration)"
   return
}

#loop on all elements and if you found as you want, break for not continue
$FirstElement=$null

$allElement=Import-csv -Path "C:\Powershell\Moje_nowe\Lista_imion3.csv" -Delimiter ";"

foreach ($item in $allElement)
{
     if ($item.Zenskie -eq $UserName)
    {
        "$UserName you are women!"
        $FirstElement=$item
        break
    }
    elseif ($item.Meskie -eq $UserName)
    {
        "$UserName you are man!"
        $FirstElement=$item
        break
    }
}

#if not element founded
if (! $FirstElement)
{
    "$UserName you have an odd name, Brrrrr !"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...