Войти

Показать полную графическую версию : [решено] использование && и || при готовом true или false


Elven
13-05-2021, 13:57
Такс, кто мне объяснит за пошик у меня мозг слегка подвисать начал от того во что я уперся:
есть такой фрагмент на баше
~ /bin/true && echo "result: OK" || echo "result: KO"
result: OK

~ /bin/false && echo "result: OK" || echo "result: KO"
result: KO
и тут всё понятно, отдаем true или false и в зависимости от принятого выводим ОК или KO. пробуем сделать аналогично в пошике:
$true 2>&1>$null && Write-Host "result: OK" || Write-Host "result: KO"
result: OK
с этим всё путём, так и ожидалось. а теперь
$false 2>&1>$null && Write-Host "result: OK" || Write-Host "result: KO"
result: OK
втф? начал глубже копаться, добавил в вывод $? дык оказывается $? возвращает true и при $true, и при $false
$true 2>&1>$null && Write-Host "result: OK ($?)" || Write-Host "result: KO ($?)"
result: OK (True)
$false 2>&1>$null && Write-Host "result: OK ($?)" || Write-Host "result: KO ($?)"
result: OK (True)

у кого есть сцыль на то чтобы почитать что-то про это дело? ну или своими словами можно, я не привередливый.

фрагменты, разумеется, до крайности упрощенные, на самом деле там многоэтажная конструкция (или многопайповая?) результатом которой является либо "true" либо "false", но не в виде "$?", а просто сами по себе. разумеется я это всё дело заменил if, но как и зачем оно так работает таки интересно.

Elven
13-05-2021, 16:01
upd: about_pipeline_chain_operators (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pipeline_chain_operators)
Если кратко и по сути: есть то что мы передаем, а есть то что пошик читает. в данном случае мы передаем конкретное значение $true или $false, а пошик смотрит исключительно в $?
и на его взгляд вывод значения переменной $false как и $true вполне даже прошел успешно (т.е. вернул в $? - true) на основе чего и строятся условия этих pipeline chain operators (как бы это культурнее перевести? операторы цепочки конвейера? или просто операторы цепочки или операторы конвейера? - любой вариант режет слух). Не могу сказать что это хорошо, хотя и не могу утверждать что плохо. Это просто так, и никак иначе.

субъективное мнение: пошик создавался не за один день, было много на него накручено, когда я добрался до try catch finally - вообще полный восторг, наконец можно скрипт просто и элегантно завернуть в адекватную обработку ероров и/или ворнингов, настроить правильные постдействия... а теперь есть официальные примеры, в которых англицким по-белому написано (хоть и несколько иносказательно): забейте на ошибки, если они таки будут - вот вам || и радуйтесь этому как хотите. Ну а если ошибки нам неинтересны то и тем более &&

YuS_2
13-05-2021, 18:48
или просто операторы цепочки или операторы конвейера? »
Как по мне, это самые, что ни на есть логические -И- и -ИЛИ-

абейте на ошибки, если они таки будут - вот вам || и радуйтесь этому как хотите. Ну а если ошибки нам неинтересны то и тем более && »
это вряд ли...
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pipeline_chain_operators?view=powershell-7.1#error-interaction
если исключение слева, то правую часть фиг получим..., что неверно в случае ||

Foreigner
13-05-2021, 19:50
если исключение слева, то правую часть фиг получим..., что неверно в случае || »


> $ErrorActionPreference = 'SilentlyContinue'
> 1/0 && $true || $false
False
> 0/1 && $true || $false
0
True

YuS_2
13-05-2021, 22:31
$ErrorActionPreference = 'SilentlyContinue' »
А это вроде, как бы и не при чем? :)
В таком варианте вообще не будет прерывающих исключений...

Foreigner
13-05-2021, 23:42
А это вроде, как бы и не при чем? »

Это чтобы подавить вывод ошибки.

YuS_2
14-05-2021, 07:53
Это чтобы подавить вывод ошибки. »
Да, это понятно... но:
Подавляя вывод ошибок при возникновении непрерывающих исключений, можем получить неожиданные результаты при разработке скрипта в целом. Можно, конечно, уповать на свою память и думать, что ошибки мы нигде не совершим, но... мне кажется, что это несколько самонадеянно. :)
Да, можно, в каждом командлете переопределять действие этой переменной параметром erroraction, но все эти действия точно нужны, для использования этих синтетических И и ИЛИ? До powershell 7.0 как-то ведь обходились без них...

Foreigner
14-05-2021, 09:02
До powershell 7.0 как-то ведь обходились без них... »

Я и сейчас не прибегаю к такой конструкции. В основном:


$ErrorActionPreference = 'Stop'

Try{}
Catch{}
Finally {} # редко


Главным образом при веб-запросах, например при обновлении FAR.

Elven
14-05-2021, 10:15
Как по мне, это самые, что ни на есть логические -И- и -ИЛИ- »
нет. или по крайней мере не совсем. даже в bash или cmd/bat это не "И" и "ИЛИ", хоть их так и называют.

Try{}
Catch{}
Finally {} »
кстати поведение || в try может стать еще более неожиданным чем мне до этого казалось.
Вот здесь всё банально и логично:
Get-ChildItem nonexistfile || $true

Get-ChildItem: Cannot find path '/path/nonexistfile' because it does not exist.
True


1/0 || $true

RuntimeException: Attempted to divide by zero.
True
Просим возвращать true если имели ошибку - такое и получаем.
А теперь заворачиваем в try-catch:
c Get-Childitem получаем ожидаемый результат
try {
Get-ChildItem nonexistfile || $true
}
catch {
Write-Error "$?"
}

Cannot find path '/path/nonexistfile' because it does not exist.

True
сиречь True, а вот с 1/0...

try {
1/0 || $true
}
catch {
Write-Error "$?"
}

Write-Error: False

внезапно вываливаемся в catch.
Вот реально!
https://d.radikal.ru/d05/2105/99/9c76b70d1f75.png

YuS_2
14-05-2021, 10:21
Я и сейчас не прибегаю к такой конструкции. »
Ну, вряд ли, эта конструкция предназначена для замены try-catch-finally, она скорее замена условному блоку, т.е. упрощение записи, а существующие -and и -or, выдают не результат выполнения операторов и их операндов, а булевый... скажем:
$(ps) -and $(write-output test)
получим True, в отличие от:
$(ps) && $(write-output test)
и до версии 7.0, подобное выражение, нам пришлось бы записать так:
ps;if($?){write-output test}
т.е. по сути, вместо && и ||, это соответственно:
function test-command ($a){return $a}
# && правый будет выполнен только если выполнен левый
test-command '1'; if ($?) {test-command '2'}
# || если левый операнд выполнен
test-command '1'; if (!$?) {test-command '2'}
# || если левый операнд не выполнен, выполняем правый
write-error 'error'; if (!$?) {test-command '2'}

нет. »
Да, только результат будет не булевым, а именно то, что выполняет левый или правый операнд, всё просто, см. выше...

даже в bash или cmd/bat это не "И" и "ИЛИ", хоть их так и называют. »
там, как раз, полные аналоги этих введеных операторов в ps 7.0

Foreigner
14-05-2021, 10:36
А теперь заворачиваем в try-catch »

На мой взгляд try-catch для этого не предназначен, его задача отловить ошибку, во всяком случае я его применяю в этом контексте -- отловить - вывести ошибку - прервать скрипт.


Try { $null = dir fakedir -ea 'stop' }
Catch { "fakedir не существует"; return }

"fakedir существует, продолжаем"

YuS_2
14-05-2021, 10:42
внезапно вываливаемся в catch. »
хмм, а у меня так:
164523

Elven
14-05-2021, 10:44
YuS_2, не тот кусок кода скопировал, мой косяк.
try {
1/0 || $true
}
catch {
Write-Error "$?"
}

Write-Error: False

его задача отловить ошибку, »
так и есть, но согласно логике описанной у ms строка
1/0 || $true

вроде как не содержит ошибки (точнее содержит, но превращает ее все равно в true), т.о. в catch вываливать не должно, но вываливается.

Foreigner
14-05-2021, 11:03
точнее содержит, но превращает ее все равно в true »

Try ее и отлавливает, оно не руководствуется конечным результатом ($true или $false не важны), а лишь отлавливает ошибку:


try {$true} # замените на $false, потом на 1/0
catch {'error'; return }

'not an error'

Elven
14-05-2021, 11:09
лишь отлавливает ошибку»
Значит отлавливает ее по-разному, иначе почему точно так же содержащая ошибку
Get-ChildItem nonexistfile || $true

возвращает True и в catch не вываливается?

Foreigner
14-05-2021, 11:17
возвращает True и в catch не вываливается? »
Потому, что ее надо прерывать:

Get-ChildItem nonexistfile -ea 1 || $true
$ErrorActionPreference = 'stop'; 1/0 || $true

Elven
14-05-2021, 11:25
Не объясняет поведения try-catch. Разумеется если дергать стоп при ошибке, то так оно и будет, но вопрос не в том как заставить пош делать так как нужно, а понять как же он вообще работает в данном случае, при находящемся $ErrorActionPreference в дефолтном Continue.

YuS_2
14-05-2021, 11:26
не тот кусок кода скопировал, мой косяк. »
угу, понятно. Ну, что тут сказать, говорю же, синтетически внедренные операторы и видимо, их до конечного результата толком не отладили...
И кстати, именно этот момент описали в документации, я же ссылку выше (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pipeline_chain_operators?view=powershell-7.1#error-interaction) приводил именно по этому поводу. Прерывающее исключение, прекращает работу операторов && и ||, т.е. завершает их работу и выдает результат только самого исключения.

Значит отлавливает ее по-разному, иначе почему точно так же содержащая ошибку
возвращает True и в catch не вываливается?
»
конечно, по-разному. try-catch-finally не ловит непрерывающие исключения.
То бишь, чтобы всё было в одинаковых условиях, должно быть так:
try {
Get-ChildItem nonexistfile -ea 1|| $true
} catch {
Write-Error "$?"
}

Elven
14-05-2021, 11:59
ок, если уровнять обе строки посредством $ErrorActionPreference = 'Stop', значит вроде как они рАвно должны отработать и при $ErrorActionPreference = 'Continue'.

YuS_2
14-05-2021, 12:17
если уровнять обе строки посредством $ErrorActionPreference = 'Stop', значит вроде как они рАвно должны отработать и при $ErrorActionPreference = 'Continue'. »
Здесь в предложении ошибка, такая переменная всего одна и значение у неё тоже единственное. Но да, если присвоить ей значение Stop, соответственно все непрерывающие исключения, становятся прерывающими. Эта переменная воздействует именно на непрерывающие исключения, на прерывающие, она никак не влияет.




© OSzone.net 2001-2012