Ternary comparison outputs new value - conditional-operator

PS C:\Users\Scott> $openlog = "YES"
PS C:\Users\Scott> ($openlog -eq "YES") ? ($openlog = "NO") : ($openlog = "YES")
NO
PS C:\Users\Scott> ($openlog -eq "YES") ? ($openlog = "NO") : ($openlog = "YES")
YES
PS C:\Users\Scott> ($openlog -eq "YES") ? ($openlog = "NO") : ($openlog = "YES")
NO
PS C:\Users\Scott> ($openlog -eq "YES") ? ($openlog = "NO") : ($openlog = "YES")
YES
PS C:\Users\Scott>
This works, ie it toggles the value, but it also writes it to the console. Why? How do I do this properly and not output the new value, without using | Out-Null?

You can use the below to set the variable without outputting to console.
$openlog = $openlog -eq "YES" ? "NO" : "YES"
I do not yet know why your example outputs to the console. I went through the implementation and this was a use case that was never handled and isn't handled during testing.
Update: as mklement0 mentions below
enclosing an assignment in (...) passes the value being assigned through

Otter's helpful answer offers the optimal solution for your use case, which bypasses the problem with your code:
As for:
it also writes it to the console. Why?
PowerShell allows you to use assignments as expressions, by enclosing them in (...), the grouping operator:
That is, something like ($var = 'foo') also outputs the value being assigned, in addition to assigning to variable $var:
PS> ($var = 'foo')
foo
That is, the value is output to PowerShell's success output stream (see the conceptual about_Redirection help topic), which by default goes to the host (console).

Related

In 'sh' how to put the result of a string comparison into a variable?

In basic 'shell', how do I put the result of a string comparison into a boolean variable?
Consider:
isweekday() {
w=$(date +%w)
if [[ $w == "0" ]] || [[ $w == "6" ]]; then
false
else
true
fi
}
One can debate whether it would be clearer or not, but is there a way to assign the result of the 'if' expression to a boolean variable, e.g.
isweekday() {
w=$(date +%w)
wd=<boolean result of [[ $w == "0" ]] || [[ $w == "6" ]]>
return $wd
}
After some experimentation, I got closer to what I want but it still isn't what I'm after:
isweekday() {
w=$(date +%w)
[[ $w == "0" ]] || [[ $w == "6" ]]
}
This works and does not require the conditional, but it looks wrong, however if you do:
if isweekday; then
echo 'weekday'
fi
you will get the right result. This seems to be because the exit code of 'true' is 0 and the exit code of 'false' is 1 (not quite sure why that is...)
There are no boolean variables. All shell variables are strings (though there are limited facilities for interpreting them as integer numbers for basic comparisons etc and basic arithmetic).
The exit code 0 is reserved for success; all other exit codes (up to the maximum 255) signify an error (though some nonstandard tools use this facility to communicate non-error results by way of convention; the caller is then assumed to understand and agree on this ad-hoc use of the exit code).
Perhaps then the simplest answer to what you appear to be asking is to save the exit code. It is exposed in the variable $?. But very often, you should not need to explicitly examine its value; indeed, your final isweekday code looks by far the most idiomatic and natural, and returns this code from [[ implicitly.
I don't understand why you think your final code "looks wrong"; this is precisely how you would use a function in a conditional.
However, in some sense, a case statement would look less cluttered here (but this syntax is somewhat jarring at first for other reasons, until you get used to it).
is_weekday () {
case $(date +%w) in
0 | 6) return 1;;
esac
return 0
}
This is portable to POSIX sh, unlike the Bash-only [[...]] syntax you were using. Perhaps see also Difference between sh and bash
The standard approach in Shell is to use the exit code of a command as the true/false value where zero indicates true and non-zero false. Also, I would instead define a function which tests if it's weekend today since that is the exception so to speak. It's also a good idea to define w as a local variable and to quote all variables which could in the general case contain a space or be undefined, something which can lead to a syntax error after variable expansion. Here is my suggestion:
IsWeekend()
{
local w="$(date +%w)"
[ "$w" = 0 ] || [ "$w" = 6 ]
}

How to switch between gcc6 and gcc8 based on a variable in powershell

I am trying to switch between gcc-6 and gcc-8 based on a variable in a powershell script. I have both installed and my ~/.bashrc file is empty.
I have in script.ps1
$gccVersion = 'gcc8'
if ($gccVersion -eq 'gcc6'){
'source /opt/rh/devtoolset-6/enable'
} else {
'source /opt/rh/devtoolset-8/enable'
}
However this does not work. It just sticks with the default gcc version no matter what variable I give it. What am I missing?
What is the easiest way to dynamically switch between gcc6 and gcc8 based on a variable?
As stated in above comment, you've the invoke the given strings. I'd try to invoke them via the &-operator, like this:
$gccVersion = 'gcc8'
if ($gccVersion -eq 'gcc6'){
& 'source /opt/rh/devtoolset-6/enable'
} else {
& 'source /opt/rh/devtoolset-8/enable'
}
# Check the last exit code and execution status
if ((-not $?) -or ($LASTEXITCODE -ne 0)) {
Write-Error "Command failed"
}
You should also check the LASTEXITCODE and the execution status of last operation.
Hope that helps.
Your if does not properly test the variable. Write it either as
if [ "$gccVersion" = gcc6 ]
or
if test $gccVersion" = gcc6
or
if [[ $gccVersion == gcc6 ]]

Shell Scripting Ternary operator to get string result

In shell scripting, I am using ternary operator like this:
(( numVar == numVal ? (resVar=1) : (resVar=0) ))
I watched shell scripting tutorial by Derek Banas and got the above syntax at 41:00 of the video
https://www.youtube.com/watch?v=hwrnmQumtPw&t=73s
The above code works when we assign numbers to resVar, but if I try to assign a string to resVar, it always returns 0.
(( numVar == numVal ? (resVar="Yop") : (resVar="Nop") ))
and also tried
resVar=$(( numVar == numVal ? (echo "Yop") : (echo "Nop") ))
So which is the right way to do this?
You didn't tell us what shell you use but it's possible you use
bash or something similar. Ternary operator in Bash works only with numbers as
explained in man bash under ARITHMETIC EVALUATION section:
The shell allows arithmetic expressions to be evaluated, under
certain circumstances (see the let and declare builtin commands and
Arithmetic Expansion). Evaluation is done in fixed-width integers
with no check for over- flow, though division by 0 is trapped and
flagged as an error. The operators and their precedence,
associativity, and values are the same as in the C language. The
following list of operators is grouped into levels of
equal-precedence operators. The levels are listed in order of
decreasing precedence.
(...)
expr?expr:expr
conditional operator
And the reason that resVar is assigned 0 when you use "Yop" or
"Nop" is because such string is not a valid number in bash and
therefore it's evaluated to 0. It's also explained in man bash in
the same paragraph:
A null value evaluates to 0.
It's also explained in this Wikipedia
article if you find it
easier to read:
A true ternary operator only exists for arithmetic expressions:
((result = condition ? value_if_true : value_if_false))
For strings there only exist workarounds, like e.g.:
result=$([ "$a" == "$b" ] && echo "value_if_true" || echo
"value_if_false")
(where "$a" == "$b" can be any condition test, respective [, can
evaluate.)
Arkadiusz already pointed out that ternary operators are an arithmetic feature in bash, not usable in strings. If you want this kind of functionality in strings, you can always use arrays:
$ arr=(Nop Yop)
$ declare -p arr
declare -a arr='([0]="Nop" [1]="Yop")'
$ numVar=5; numVal=5; resvar="${arr[$((numVar == numVal ? 1 : 0))]}"; echo "$resvar"
Yop
$ numVar=2; numVal=5; resvar="${arr[$((numVar == numVal ? 1 : 0))]}"; echo "$resvar"
Nop
Of course, if you're just dealing with two values that can be in position 0 and 1 in your array, you don't need the ternary; the following achieves the same thing:
$ resvar="${arr[$((numVar==numVal))]}"
you can use this simple expression :
resVar=$([ numVar == numVal ] && echo "Yop" || echo "Nop")
Running with Gohti's idea to make the script more readable:
#!/bin/bash
declare -a resp='([0]="not safe" [1]="safe")'
temp=70; ok=$(( $temp > 60 ? 1 : 0 ))
printf "The temperature is $temp Fahrenheit, it is ${resp[$ok]} to go outside\n";
temp=20; ok=$(( $temp > 60 ? 1 : 0 ))
printf "The temperature is $temp Fahrenheit, it is ${resp[$ok]} to go outside\n";

if: Expression syntax Error in csh - not to accept other string than the only string it must accept

There's this daemon with, for ex. 5 types in one script. Now, i want to be able to start/stop it by specifying the number of the daemon(to start one by one), OR specify "all" (to start in bulk).
The format: (runscript) (commandName) (daemon # or "all")
Need to satisfy two conditions, when the user inputs: (1) correctly (either by number or "all) OR
(2) incorrectly (either inputted num is greater than $count or all other string than "all").
All conditions are already achieved except for one, if the user inputs other string than "all"
Sample code:
case 'startDaemon': #commandName
set count = 5
if ($#argv == 2 && $2 == all) then
echo "correct, do this"
else if ($#argv == 2 && $2 < $count) then
echo "correct too, do this"
else if ($#argv == 2 && ($2 != all || $2 >= $count)) then
echo "Incorrect parameter: specify daemon # less than $count or 'all' to start all."
else
echo "Please use: $0(runscript) $1(commandname) (daemon # or all)"
whenever I type: (runscript) startDaemon hello, for example, error shows:
if: Expression syntax
When it should have gone to the 3rd condition. Please help and kindly point out if the prob is in the conditions or logical operators or whatever. Thanks in advance
PS. Im using csh. The script given to me is in csh, so yep.
The immediate problem is the comparison $2 < $count, which is invalid when $count contains a string.
Here is a working solution:
#!/bin/csh
set count = 5
if ($#argv == 2) then
if ($2 == all) then
echo "correct, do this"
else if (`echo $2 | grep '^[0-9]*$'`) then
if ($2 < $count) then
echo "correct too, do this"
else
echo "Number must be less than 5"
endif
else
echo "Incorrect parameter: specify daemon # less than $count or 'all' to start all."
endif
else
echo "Please use: $0(runscript) $1(commandname) (daemon # or all)"
endif

ksh function return value in parentheses

In the following very simple ksh script example, I need to ask if func1 results equal to 4 ,
This is what I did in the example but this script does not print the "function result = 4" as I expected it to.
What do I need to change in the [[......]] in order to print the "function result = 4"
Remark - func1 must be in the [[.....]]
#!/bin/ksh
func1()
{
return 4
}
[[ ` func1 ` = ` echo $? ` ]] && print "function result = 4"
You need
#!/bin/ksh
func1()
{
print -- 4
}
[[ $(func1) = 4 ]] && print "function result = 4"
OR
#!/bin/ksh
func1()
{
return 4
}
func1 ; [[ $? == 4 ]] && print "function result = 4"
There are several issues in the code that you present, so let me try to explain (You're making it more complicated than it need be).
No. 1 is your use of back-ticks for command substitution, these have been deprecated in the ksh language since ~ 1995! Use $( ... cmd ) for modern cmd-substitution. We often see backticks listed as a nod to portability, but only scripts written for systems where the Bourne shell is the only shell available require the use of backticks. (well, I don't know about dash or ash, so maybe those too).
No 2. is that $? gets set after ever function or command or pipeline is executed and is the return code of that last command. It is a value between 0-255. When you have code like cmd ; rc=$? ; echo $? ; you're now echoing the status of the assignment of rc=$? (which will almost always be 0), AND that is why you will see experienced scriptors save the value of $? before doing anything else with it.
Recall that command-substitution uses what ever is the output of the $( ... cmd ...) or backtics enclosed command while return sets the value of $? (until the very next command execution resets that value).
I hope this helps.
Function does return 4. The operator `` (backticks) ignores the result value, and returns the function's stdout instead (in your case an empty string, since func1 did not print anything to stdout).
And
`echo $?`
is just over-complicated way of saying
$?

Resources