Каковы PowerShell-эквиваленты Bash's && и || операторы?

В Bash я легко могу сделать что-то вроде

command1 && command2 || command3

что означает запуск команды command1, и если command1 удается выполнить command2 и если command1 не удается запустить command3.

Что эквивалентно в PowerShell?

3 ответа

Решение

То, что должен делать Bash, это неявное приведение кода завершения команд к логическому значению при передаче логическим операторам. PowerShell этого не делает, но можно создать функцию для переноса команды и создания того же поведения:

> function Get-ExitBoolean($cmd) { & $cmd | Out-Null; $? }

( $? это логическое значение, содержащее успех последнего кода выхода)

Даны два пакетных файла:

#pass.cmd
exit

а также

#fail.cmd
exit /b 200

... поведение можно проверить:

> if (Get-ExitBoolean .\pass.cmd) { write pass } else { write fail }
pass
> if (Get-ExitBoolean .\fail.cmd) { write pass } else { write fail }
fail

Логические операторы должны оцениваться так же, как в Bash. Сначала установите псевдоним:

> Set-Alias geb Get-ExitBoolean

Тестовое задание:

> (geb .\pass.cmd) -and (geb .\fail.cmd)
False
> (geb .\fail.cmd) -and (geb .\pass.cmd)
False
> (geb .\pass.cmd) -and (geb .\pass.cmd)
True
> (geb .\pass.cmd) -or (geb .\fail.cmd)
True

Через много лет после того, как вопрос был впервые задан, позвольте мне кратко изложить ситуацию с PowerShell v5.1:

  • Баш / cmd "s && а также || операторы управления не имеют эквивалентов PowerShell, и, поскольку вы не можете определить пользовательские операторы в PowerShell, хороших обходных путей нет:

    • Используйте отдельные команды (в отдельных строках или через ;), и явно проверять статус успешности каждой команды с помощью автоматической переменной $?, такие как:
      command1 -arg1 -arg2; if ($?) { command2 -arg1 } # equivalent of &&
      command1 -arg1 -arg2; if (-not $?) { command2 -arg1 } # equivalent of ||

    • Смотрите ниже, почему PowerShell -and а также -or как правило, не являются решением.

  • Был разговор о добавлении их некоторое время назад, но это, казалось, никогда не занимало верхнюю строчку списка.

    • Теперь, когда PowerShell стал открытым, появилась проблема на GitHub.
    • Жетоны && а также || в настоящее время зарезервированы для будущего использования в PowerShell, поэтому есть надежда, что тот же синтаксис, что и в Bash, может быть реализован.
      (По состоянию на PSv5.1, попытка что-то вроде 1 && 1 выдает сообщение об ошибке The token '&&' is not a valid statement separator in this version.)

Почему PowerShell -and а также -or не заменит && а также ||:

Операторы управления Bash && (короткое замыкание логического И) и || (короткое замыкание логического ИЛИ) неявно проверяет статус успешности команд по их кодам выхода, не влияя на их выходные потоки; например:

ls / nosuchfile && echo 'ok'

Без разницы ls выходы - оба вывода stdout (файлы в /) и вывод stderr (сообщение об ошибке при попытке доступа к несуществующему файлу nosuchfile) - пройдено, но && проверяет (невидимый) код выхода ls Команда, чтобы решить, если echo Команда - RHS из && управляющий оператор - должен быть выполнен.

ls код выхода отчетов 1 в этом случае сбой сигнализации - потому что файл nosuchfile не существует - так && решает, что ls не удалось, и, применяя короткое замыкание, решает, что echo Команда не должна быть выполнена.
Обратите внимание, что это код выхода 0 что свидетельствует об успехе в мире cmd.exe а также bash тогда как любой ненулевой код выхода указывает на сбой.

Другими словами: Баш && а также || работают полностью независимо от вывода команд и действуют только на статус успешности команд.


PowerShell - х -and а также -or напротив, действуйте только на стандартный (успешный) вывод команды, потребляйте его и затем выводите только логический результат операции; например:

(Get-ChildItem \, nosuchfile) -and 'ok'

Выше:

  • использует и потребляет успешный (стандартный) вывод - список \ - и интерпретирует это как логическое значение; непустая входная коллекция считается $true в логическом контексте, поэтому, если есть хотя бы одна запись, выражение оценивается как $true,

    • Тем не менее, информация об ошибке в результате несуществующего файла nosuchfile пропущен, потому что ошибки отправляются в отдельный поток.
  • При условии Get-ChildItem \, nosuchfile возвращает непустой результат успешной работы, LHS оценивается как $true, так -and также оценивает RHS, 'ok', но, опять же, потребляет свои выходные данные и интерпретирует их как логическое значение, которое, как непустая строка, также оценивается как $true,

  • Таким образом, общий результат -and выражение $true, который является (единственным успехом) выходным.

Чистый эффект:

  • Успешный результат с обеих сторон -and выражение потребляется во время оценки и, следовательно, эффективно скрыты.

  • Единственным (успешным) выводом выражения является его логический результат, который $true в этом случае (что делает как True в терминале в англоязычных системах).

Вы можете сделать что-то вроде этого, где вы скрываете логический вывод с помощью [void] и получаете только побочный эффект. В этом случае, если $a или $b равны нулю, $c присваивается $result. Присвоение может быть выражением.

$a = ''
$b = ''
$c = 'hi'

[void](
  ($result = $a) -or
  ($result = $b) -or
  ($result = $c))

$result

выход

hi

Мы можем использовать метод try catch finally вместо метода && в powershell.

try {hostname} catch {echo err} finally {ipconfig /all | findstr bios}
Другие вопросы по тегам