tc shell script: undefined variable - shell

Can someone tell me what I am doing wrong with set flag1.. i am getting an error of flag1: Undefined variable.
if($notLoaded1 > 0) then
echo "Rows not loaded due to data errors in first load: $notLoaded1"
set flag1=1
endif
if($notLoaded2 > 0) then
echo "Rows not loaded due to data errors in second load: $notLoaded2"
set flag2=1
endif
if($notLoaded3 > 0) then
echo "Rows not loaded due to data errors in third load: $notLoaded3"
set flag3=1
endif
echo $flag1
echo $flag2
echo $flag3
is there a way to check all three of them in one if statement or rather than using 3 if statements
if ($flag1 > 0) then
exit 1
endif
if ($flag2 > 0) then
exit 1
endif
if ($flag3 > 0) then
exit 1
endif
Thank you

What do you need 3 flag variables for?
set error=0
if ($notLoaded1 > 0) then
echo "Rows not loaded due to data errors in first load: $notLoaded1"
set error=1
endif
if ($notLoaded2 > 0) then
echo "Rows not loaded due to data errors in second load: $notLoaded2"
set error=1
endif
if ($notLoaded3 > 0) then
echo "Rows not loaded due to data errors in third load: $notLoaded3"
set error=1
endif
if ($error) then
exit 1
endif

flag1 only gets set if $notLoaded1 is greater than 0. So if it's zero, you don't get a $flag1.
I'd suggest initializing those three variables with defaults beforehand:
set flag1=0
if (...) the
set flag1=1
echo 'Rows not loaded...'
endif
That'll guarantee that flag1 always exists.

Related

variable set in brace group doesn't keep value outside

When a variable is set inside braced statements, the value is also known outside.
{ i=4; } ; echo "$i" will output 4.
I wanted to be clever and use that to transmit metadata alongside some data (that can contain null-bytes - so no variables).
So my program pipes some data into a braced group of statements where it is read - as expected - but the variables aren't changed outside and I can't find the part of the spec that says they shouldn't.
My first guess was that a sneaky subshell was created cause of the pipe but I've checked the PID in- and outside.
Reading into a temp variable and then assigning to the outside var also doesn't work.
Here's some code to reproduce (the error ;-):
finished=0
pos=0
echo "pid outside: $$"
(
# placeholder code
echo 1
echo 1
echo "data"
) | {
echo "pid inside: $$"
read pos
read finished
echo "pos: $pos"
echo "finished: $finished"
# instead of the echos, cat would output the data here
}
echo "pos outside: $pos"
echo "finished outside: $finished"
Output:
pid outside: 139840
pid inside: 139840
pos: 1
finished: 1
pos outside: 0
finished outside: 0
What am I missing?

Tcsh Script Last Exit Code ($?) value is resetting

I am running the following script using tcsh. In my while loop, I'm running a C++ program that I created and will return a different exit code depending on certain things. While it returns an exit code of 0, I want the script to increment counter and run the program again.
#!/bin/tcsh
echo "Starting the script."
set counter = 0
while ($? == 0)
# counter ++
./auto $counter
end
I have verified that my program is definitely returning with exit code = 1 after a certain point. However, the condition in the while loop keeps evaluating to true for some reason and running.
I found that if I stick the following line at the end of my loop and then replace the condition check in the while loop with this new variable, it works fine.
while ($return_code == 0)
# counter ++
./auto $counter
set return_code = $?
end
Why is it that I can't just use $? directly? Is another operation underneath the hood performed in between running my custom program and checking the loop condition that's causing $? to change value?
That is peculiar.
I've altered your example to something that I think illustrates the issue more clearly. (Note that $? is an alias for $status.)
#!/bin/tcsh -f
foreach i (1 2 3)
false
# echo false status=$status
end
echo Done status=$status
The output is
Done status=0
If I uncomment the echo command in the loop, the output is:
false status=1
false status=1
false status=1
Done status=0
(Of course the echo in the loop would break the logic anyway, because the echo command completes successfully and sets $status to zero.)
I think what's happening is that the end that terminates the loop is executed as a statement, and it sets $status ($?) to 0.
I see the same behavior with both tcsh and bsd-csh.
Saving the value of $status in another variable immediately after the command is a good workaround -- and arguably just a better way of doing it, since $status is extremely fragile, and will almost literally be clobbered if you look at it.
Note that I've add a -f option to the #! line. This prevents tcsh from sourcing your init file(s) (.cshrc or .tcshrc) and is considered good practice. (That's not the case for sh/bash/ksh/zsh, which assign a completely different meaning to -f.)
A digression: I used tcsh regularly for many years, both as my interactive login shell and for scripting. I would not have anticipated that end would set $status. This is not the first time I've had to find out how tcsh or csh behaves by trial and error and been surprised by the result. It is one of the reasons I switched to bash for interactive and scripting use. I won't tell you to do the same, but you might want to read Tom Christiansen's classic "csh.whynot".
Slightly shorter/simpler explanation:
Recall that with tcsh/csh EACH command (including shell builtin) return a status. Therefore $? (aliases to $status) is updated by 'if' statements, 'for' loops, assignments, ...
From practical point of view, better to limit the usage of direct use of $? to an if statement after the command execution:
do-something
if ( $status == 0 )
...
endif
In all other cases, capture the status in a variable, and use only that variable
do-something
something_status=$?
if ( $something_status == 0 )
...
endif
To expand on the $status, even a condition test in an if statement will modify the status, therefore the following repeated test on $status will not never hit the '$status == 5', even when do-something will return status of 5
do-something
if ( $status == 2 ) then
echo FOO
else if ( $status == 5 ) then
echo BAR
endif

syntax error: unexpected end of file when running source

I have been trying to source this script from Xilinx install but it outputs an error.
source /opt/Xilinx/14.7/ISE_DS/settings32.csh
# Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved.
set SETTINGS_FILE=.settings32.csh
set XIL_SCRIPT_LOC="/opt/Xilinx/14.7/ISE_DS"
if ( $# != 0 ) then
# The first argument is the location of Xilinx Installation.
# Don't detect the installation location.
set XIL_SCRIPT_LOC="$1"
else
# XIL_SCRIPT_LOC should point to script location
set XIL_SCRIPT_LOC_TMP_UNI=`echo $_ | cut -d" " -f 2`
set XIL_SCRIPT_LOC_TMP_UNI_TAIL=${XIL_SCRIPT_LOC_TMP_UNI:t}
set XIL_SCRIPT_LOC_TMP_UNI=${XIL_SCRIPT_LOC_TMP_UNI:h}
if ( "$XIL_SCRIPT_LOC_TMP_UNI" != "" ) then
if ( "$XIL_SCRIPT_LOC_TMP_UNI" == "$XIL_SCRIPT_LOC_TMP_UNI_TAIL" ) then
set XIL_SCRIPT_LOC_TMP_UNI="./"
endif
set XIL_SCRIPT_LOC_TMP_UNI=`readlink -f ${XIL_SCRIPT_LOC_TMP_UNI}`
if ( $? == 0 ) then
set XIL_SCRIPT_LOC=${XIL_SCRIPT_LOC_TMP_UNI}
endif
endif
unset XIL_SCRIPT_LOC_TMP_UNI_TAIL
unset XIL_SCRIPT_LOC_TMP_UNI
endif
set xlnxInstLocList=""
set xlnxInstLocList="${xlnxInstLocList} common"
set xlnxInstLocList="${xlnxInstLocList} EDK"
set xlnxInstLocList="${xlnxInstLocList} PlanAhead"
set xlnxInstLocList="${xlnxInstLocList} ISE"
set XIL_SCRIPT_LOC_TMP_UNI=${XIL_SCRIPT_LOC}
foreach i $( xlnxInstLocList )
set d="${XIL_SCRIPT_LOC_TMP_UNI}/$i"
set sfn="$d/$SETTINGS_FILE"
if ( -e "$sfn" ) then
echo source "$sfn" "$d"
source "$sfn" "$d"
endif
end
bash: /opt/Xilinx/14.7/ISE_DS/settings32.csh: line 42: syntax error:
unexpected end of file
Can someone see the error in the script?

Return value of function in IF statement shows strange behaviour

Can anyone explain what is going on here?
Why does an "IF" statement think the return is '1' (not Null) when i say 'Return 0' and the other way round.
I found that out while coding another script, so i developed this small script to test it:
#!/bin/bash
function testreturnzero()
{
echo $1
return 0
}
function testreturnone()
{
echo $1
return 1
}
if (testreturnzero 1) || (testreturnzero 2)
then
echo "zero returned '1'"
fi
if (testreturnone 1) || (testreturnone 2)
then
echo "one returned '1'"
fi
The IF which refers to the 'return 0' thinks its true (and doesn't process the second function), the IF which refers to 'return 1' thinks its false. Shouldn't it be the exact opposite?
1
zero returned '1'
1
2
I cant put the return value in a variable as I will have several of those checks.
In bash, a function returning 0 means success and returning a non-zero value means failure. Hence your testreturnzero succeeds and your testreturnone fails.
Does that help understanding why your ifs behave that way? (it should!).
The return code of the last executed command/function is stored in the special variable $?.
So:
testreturnzero 0
ret_testreturnzero=$?
testreturnone 1
ret_testreturnone=$?
echo "$ret_testreturnzero"
echo "$ret_testreturnone"
will output (the two last lines):
0
1
Now you may think of storing them in a variable (as here) and do your logic processing later. But there's a catch :). Because you didn't store true and false in variables, you stored 0 and 1 (bash can't store booleans in a variable). So to check success or failure later:
if ((ret_testreturnzero==0)); then
echo "testreturnzero succeeded"
fi
or
if ((ret_testreturnzero!=0)); then
echo "testreturnzero failed"
fi
In bash, the return code of a function is the same as a external program when you test the result.
So for test, a valid return code is 0 and an invalid is any other number
so, by doing
if ( testreturnone 1 ); then #it is ok
echo "error"; #it's supposed to happen, not an error
fi
You can explicitly test the value to the one you want to clear it up:
if [[ "$(testreturnzero 1)" = "1"); then #it is ok if you decide that 1 is the good value
echo "ok"; #But absolutly not the bash philosophy
fi

Check if process returns 0 with batch file

I want to start a process with a batch file and if it returns nonzero, do something else. I need the correct syntax for that.
Something like this:
::x.bat
#set RetCode=My.exe
#if %retcode% is nonzero
handleError.exe
As a bonus, you may consider answering the following questions, please :)
How to write a compound statement with if?
If the application My.exe fails to start because some DLL is missing will my if work? If not, how can I detect that My.exe failed to start?
ERRORLEVEL will contain the return code of the last command. Sadly you can only check >= for it.
Note specifically this line in the MSDN documentation for the If statement:
errorlevel Number
Specifies a true
condition only if the previous program
run by Cmd.exe returned an exit code
equal to or greater than Number.
So to check for 0 you need to think outside the box:
IF ERRORLEVEL 1 GOTO errorHandling
REM no error here, errolevel == 0
:errorHandling
Or if you want to code error handling first:
IF NOT ERRORLEVEL 1 GOTO no_error
REM errorhandling, errorlevel >= 1
:no_error
Further information about BAT programming: http://www.ericphelps.com/batch/
Or more specific for Windows cmd: MSDN using batch files
How to write a compound statement with
if?
You can write a compound statement in an if block using parenthesis. The first parenthesis must come on the line with the if and the second on a line by itself.
if %ERRORLEVEL% == 0 (
echo ErrorLevel is zero
echo A second statement
) else if %ERRORLEVEL% == 1 (
echo ErrorLevel is one
echo A second statement
) else (
echo ErrorLevel is > 1
echo A second statement
)
This is not exactly the answer to the question, but I end up here every time I want to find out how to get my batch file to exit with and error code when a process returns an nonzero code.
So here is the answer to that:
if %ERRORLEVEL% NEQ 0 exit %ERRORLEVEL%
The project I'm working on, we do something like this. We use the errorlevel keyword so it kind of looks like:
call myExe.exe
if errorlevel 1 (
goto build_fail
)
That seems to work for us. Note that you can put in multiple commands in the parens like an echo or whatever. Also note that build_fail is defined as:
:build_fail
echo ********** BUILD FAILURE **********
exit /b 1
To check whether a process/command returned 0 or not, use the operators && == 0 or not == 0 ||:
Just add operator to your script:
execute_command && (
echo\Return 0, with no execution error
) || (
echo\Return non 0, something went wrong
)
command && echo\Return 0 || echo\Return non 0
For details on Operators' behavior see: Conditional Execution || && ...
You can use below command to check if it returns 0 or 1 :
In below example, I am checking for the string in the one particular file which will give you 1 if that particular word "Error" is not present in the file and if present then 0
find /i "| ERROR1 |" C:\myfile.txt
echo %errorlevel%
if %errorlevel% equ 1 goto notfound
goto found
:notfound
exit 1
:found
echo we found the text.

Resources