csh inline if statements - if-statement

I'm trying to add a script to check conditions before executing a command in my .cshrc file. This checker script returns 0 if the conditions are insufficient, and 1 otherwise. (I realize this is backwards of convention, but I thought it would be easier for if statements.)
Here is what I've tried, replacing the command with echo "ok":
./checker.sh && echo "ok"
Echoes "ok" even though checker.sh returns 0.
test ./checker.sh && echo "ok"
Echoes "ok" even though checker.sh returns 0, but also suppresses error messages in checker.sh.
if ( ./checker.sh ) then echo "ok" endif
Throws an if-statement syntax error.
I want to turn this into an alias, hence the one-line constraint, e.g.
alias doAction './checker.sh && echo "ok"'
How does one accomplish this with (t)csh without directly calling the command in the checker script?
Thanks!

I changed the script to exit 0 when there is NO problem, and exit a nonzero number when there is a problem. Then
./checker.sh && echo "ok"
behaves as desired...
Note to others who may read this: the above "test" construct is not equivalent to the C-style if-statement
if(./checker.sh){
echo "ok"
}

Related

How GNU treats a failure indicator from main

I write a simple case to see how my system treats a failure indicator from main.
But nothing happened. I really want to know what's the difference between return 0 and return -1.
int main()
{
return -1;
}
That depends on what your "system" is. If you just run a program then this value is ignored.
The only time this is used is if your program is part of a larger workflow where your program's failure matters. For example, a makefile (or a C++ IDE) will stop building the program if there's a failure in one of the steps. This failure is signaled by an error code from main().
most of the times, the return value in main has no use, traditionally, we return 0 to indicate the program is success, especially in Windows. But in Linux, we often have a chain of programs, which means the second program's state depends on the first one's result. At that time, the return value has its position.
So, no matter what the return value is, most of the times its depends on your design, and it means nothing to system.
Hope that can help you.
Assuming you have compiled an executable named a.out, consider:
$ ./a.out # ignore the value returned from main
$ ./a.out && echo success # check the value returned from main
$ ./a.out || echo failure
In the second and third case, the echo will only occur if a.out is successful or not, respectively, where success is defined as returning zero from main. This is a convention that may be more clear with the following syntax:
if ./a.out; then
echo a.out returned zero from main
else
echo a.out returned non-zero from main
fi
The return value of main() is available:
To the shell, if the shell started it, as $status etc, depending on which shell you're using.
To the program that started it, via the status variable pointed to by the argument to wait(). See man 2 wait().
GNU has precisely nothing do to with it.
If using the bash shell (or similar), you can show the return value of the last command executed with echo $?. Sample bash terminal session:
$false
$echo $?
1
$true
$echo $?
0
$
On other systems the return value will be accessed differently. On DOS or Windows the return value can be checked with the ERRORLEVEL command or %ERRORLEVEL% variable.

Windows Command Line Processor: Multiple and Nested IF Statements

Intended software: windows command line processor (version 6.1.7601.17514)
Hi,
I've been trying to build a multiple-statement command line that runs within a short-cut. My goal is to be able to click one short-cut that checks if my hosted network is started or not, and then takes appropriate action based on the check. The code that starts and stops the hosted network is fine, and for the most part, the logic works, but I notice odd behavior when I check the outputs of the logic. I suspect that my problem has to do with the way I structured the statements, but I'm having difficulty properly interpreting the built-in documentation and the documentation I can find in the MSDN library. If it's possible, I want to avoid using batch files for this solution.
To keep things simple, I've substituted my lengthy "netsh" commands with "echo" commands that show the errorcode. The code below is what I'm using to test my logic:
Test Code
netsh wlan show hostednetwork | find "Not" && echo found %errorlevel% || echo lost %errorlevel%
Currently, the way I'm reading this is:
Show me hostednetwork's status and send the output to input
Attempt to find the string "Not" in the input
If the attempt succeeds, output "found" and the errorcode to the screen
If the attempt fails, then output "lost" and the errorcode to the screen
Notice that I'm not using any flags on the find command. I'm doing this because I want to reduce the chance of finding a false match. To clarify what I mean, I'll show the output if I just put in
netsh wlan show hostednetwork:
Sample Output of Hostednetwork Status
C:\Windows\system32>netsh wlan show hostednetwork
Hosted network settings
-----------------------
Mode : Allowed
SSID name : "TestHost"
Max number of clients : 100
Authentication : WPA2-Personal
Cipher : CCMP
Hosted network status
---------------------
Status : Not started
If I search for the string "Not", then that's sufficient to tell me that the hosteadnetwork is not started, because when the hosteadnetwork is started, the output shows "Started".
The way I'm simulating the conditions of the hostednetwork is with the following commands:
netsh wlan start hostednetwork
netsh wlan stop hostednetwork
I expect that when I open a command prompt (as an administrator):
If the hostednetwork is not started, I should see a "found 0" in the output, meaning that the string was found and that there were no errors.
If the hostednetwork is started, I should see a "lost 1" in the output, meaning that the string was not found and that there was an error.
Case #1 works, but case #2 doesn't work on the first try. Here's my output when the hostednetwork is already started:
Output With Hostednetwork Started
C:\Windows\system32>netsh wlan start hostednetwork
The hosted network started.
C:\Windows\system32>netsh wlan show hostednetwork | find "Not" && echo found %er
rorlevel% || echo lost %errorlevel%
lost 0
C:\Windows\system32>netsh wlan show hostednetwork | find "Not" && echo found %er
rorlevel% || echo lost %errorlevel%
lost 1
Other Attempted Solutions
The way I've written the test code is the best I could come up with so far. In previous attempts, I've tried:
Setting a custom variable instead of using the errorlevel variable, but I get the same output on case #2.
Changing the code into an if else equivalent, but that didn't pan out very well.
Wrapping the conditional statements in brackets "()" after the pipe and using different combinations of the special symbols "&" and "|".
Other Questions
This question is related to another that I've been trying to figure out. If I wanted to search for three different strings in a command's output and exit on a different error code for each string, how can I do this? The syntax below is my starting point:
myCommand [/options] | ((find "string1" && exit /b 2 || ver>nul) &&
(find "string2" && exit /b 3 || ver>nul) && (find "string3" && exit /b 4 || ver>nul))
For the same reasons above, I didn't use any flags on the "find" commands. Also, I used "ver>nul" in an attempt to keep the syntax correct since I know the "ver" operation succeeds.
Any assistance is appreciated.
I don't understand why you want to avoid use of a batch script. Your shortcut can simply point to a small batch script, and life will be much easier.
But it is possible to do what you want. The value of %errolevel% is determined during parsing, and the entire shortcut is parsed in one pass, so you get the value that existed prior to execution of your FIND commands. You need delayed expansion !errorlevel! to get your desired results.
In batch you use setlocal enableDelayedExpansion, but that does not work from the command line (or a shortcut). Instead you must instantiate an extra CMD.EXE with the /V:ON option.
netsh wlan show hostednetwork | cmd /v:on /c "find "Not" && echo found !errorlevel! || echo lost !errorlevel!"
There are multiple levels of quoting going on, and that can sometimes cause problems. You can eliminate the quotes enclosing the command if you escape the special characters.
netsh wlan show hostednetwork | cmd /v:on /c find "Not" ^&^& echo found !errorlevel! ^|^| echo lost !errorlevel!
Regarding your 2nd question, I see 2 problems.
1) I don't understand the point of having a shortcut designed to exit with different error codes. How can you possibly make use of the returned error code?
2) You cannot pipe content into multiple FIND commands. The first FIND command will consume all the content and close the pipe, and then subsequent FIND commands will wait indefinitely for content from the keyboard.
You would have to redirect your command output to a temp file, and then redirect input of each FIND command to the temp file.
You cannot evaluate a variable in the same line. It needs delayed expansion and !errorlevel! to be used.
Do it in a batch file and you won't have a problem using delayed expansion.

Comparison operator substitution for IF from FOR cycle in batch scripts

I would like to ask your help in a possibly simple situation (where the solution is yet unknown for me).
I am trying to provide a variable for the if command to make a bit more "dynamic" the code, but this fails for me with:
% was unexpected at this time.
Here is a simple example for that:
> for %i in (NEQ) do (if 1 %i 2 echo jo)
%i was unexpected at this time.
While the following works like charm:
>set oper=NEQ
>for %i in (NEQ) do (if 1 %oper% 2 echo works)
works
As I should stay in the for loop (and I get the actual operator from the for loop in the real code), I am really stuck how to solve it...
Tried to play with EnableDelayedExpansion as well, but !variable! instead of the operator is refused as well. Is there a way to submit the variable in a FOR loop for IF, without major modifications in the script?
Is there a way to submit the variable in a FOR loop for IF?
No!
Because, the IF statement has it's own parser and it expects some tokens already expanded at this parse phase.
So it's neither possible to expand the options nor the operator, nor NOT.
But it's allowed to expand the values with delayed or FOR-variables.
setlocal EnableDelayedExpansion
set myOperator=EQU
IF 1 %myOperator% 1 echo Works
IF 1 !myOperator! 1 echo FAILS
for %%O in (EQU) do IF 1 %%O 1 echo Works
The percent expansion works, as it is expanded before the IF parser gets the line.
If you really need to use variable operators, then you need to use a function.
for %%O in (EQU) do call :myFunc %%O
exit /b
:myFunc
IF ONE %1 ONE echo Works
exit /b
EDIT:
And the special parser is also the cause, that it's not possible to use here a CALL expansion for the IF statement.
Like this idea
set myOperator=EQU
CALL IF 1 %%myOperator%% 1 echo Works
This should expand to IF 1 EQU 1 echo Works, but the combination of CALL and IF fails always.

If statement works the first time, but not the second time

I'm having this problem with the ** IF NOT processed == %true% **.
The problem is that it's staying in the loop when it shouldnt.
I tried the otherway around IF processed == %false% it goes in the loop BUT doesnt go back in the 2nd time. sometimes, it goes in up to 3 times.
my "echo !processed! process" is always giving me the right number but the IF statement is just not processing the second time around
%TRUE% AND %FALSE% are global variable 1 and 0
setlocal
:loopapp
**if not '!processed!'=='%TRUE%'** (
set /a count+=1
"%ProgramFiles%\abc\abc.exe" !file! !post!
call :ERRORCODES !file! !post! !ERRORLEVEL! !count!
goto :loopapp
)
endlocal
:ERRORCODES
setlocal
if %errornum% LEQ 99 (
set no_license=%FALSE%
if '!post!'== 'A' set no_license=%TRUE%
if '!no_license!'=='%TRUE%' (
echo Searching ... '!count!' ... Please Wait ...
if !count! EQU 5 (
set execute=%TRUE%
set succes=%FALSE%
echo %~n1 - Fatal - process %TIME% >> %tempfolder%\errorlog.txt
goto :END
)
set execute=%FALSE%
set succes=%FALSE%
goto :out_errorcodes
)
set execute=%TRUE%
set succes=%FALSE%
echo %~n1 - Fatal - process %TIME% >> %tempfolder%\errorlog.txt
goto :out_errorcodes
)
... other errors
:out_errorcodes
endlocal & set processed=%execute% & set fait=%succes%
goto :EOF
1) I don't see where you define what TRUE and FALSE are - they are certainly not standard batch values.
If you are trying to set up variables that function as boolean flags, then I recommend the following.
To set the flag to false, use SET "FLAG=". This "undefines" the flag.
To set the flag to true, use SET "FLAG=1. Note that the value 1 has no significance. You could use any value as long as it is not empty.
To test if the flag is true use IF DEFINED FLAG ECHO FLAG IS TRUE
To test if the flag is false use IF NOT DEFINED FLAG ECHO FLAG IS FALSE
The reason I like this technique is that DEFINED is evaluated at execution time, not parse time. So it is safe to use this test within any block of code such as within a FOR loop, and you don't have to worry about delayed expansion.
2) I haven't bothered to try to trace your logic. It would be good if you can come up with a minimal amount of code that demonstrates the problem.
3) If you have used ECHO OFF elsewhere, try setting ECHO ON just prior to the IF so that you can see what the batch script is attempting to do.
(I thought perhaps you were missing SETLOCAL EnableDelayedExpansion, but now I see your report that echo !processed! process works.)
The reason your subprogram does not seem to work is because you made a little error in it.
endlocal & set processed=%execute% & set fait=%succes%
You have a space between %execute% and &.
That space will also be in the %processed% variable's value.
So in your if statement this will be true
'!processed!'=='%TRUE% '
To avoid having that space in the %processed% variable use this
endlocal & set processed=%execute%& set fait=%succes%
This is also documented on SS64

Checking return value of a C++ executable through shell script

I am running a shell script on windows with cygwin in which I execute a program multiple times with different arguments each time. Sometimes, the program generates segmentation fault for some input arguments. I want to generate a text file in which the shell script can write for which of the inputs, the program failed. Basically I want to check return value of the program each time it runs. Here I am assuming that when program fails, it returns a different value from that when it succeeds. I am not sure about this. The executable is a C++ program.
Is it possible to do this? Please guide. If possible, please provide a code snippet for shell script.
Also, please tell what all values are returned.
My script is .sh file.
The return value of the last program that finished is available in the environment variable $?.
You can test the return value using shell's if command:
if program; then
echo Success
else
echo Fail
fi
or by using "and" or "or" lists to do extra commands only if yours succeeds or failed:
program && echo Success
program || echo Fail
Note that the test succeeds if the program returns 0 for success, which is slightly counterintuitive if you're used to C/C++ conditions succeeding for non-zero values.
if it is bat file you can use %ERRORLEVEL%
Assuming no significant spaces in your command line arguments:
cat <<'EOF' |
-V
-h
-:
-a whatnot peezat
!
while read args
do
if program $args
then : OK
else echo "!! FAIL !! ($?) $args" >> logfile
fi
done
This takes a but more effort (to be polite about it) if you must retain spaces. Well, a bit more effort; you probably use an eval in front of the 'program'.