Nesting if statements inside a while loop - C shell - while-loop

I have to write a tcsh script for unix that pulls values from every other line in a text file, compares them and decides if you should buy(1), sell(-1) or do nothing(0). Basically a simple stock profit calculation. I think I have all the logic right, but when I run the script I get a "while syntax error" and it never executes. I have the full script below, is it not possible to nest statements in a while loop with unix? If so any suggestions how to do this?
#!/bin/tcsh
set lineNum='wc -l testcase.txt'
set i=1
while ($i<$lineNum)
set prices='sed -n '$lineNump' testcase.txt'
set arr=( $price )
set j='echo ${#arr}'
set price=0
set x=0
set y=0
set k=0
while ($k < $j)
set a=arr[$k]
set str=""
if ($a>$price)
then
str="$str 1"
price=$((price-a))
else if($a<$price)
then
str="$str -1"
price=$((price+a))
else if($a==$price)
then
str="$str 0"
fi
str="$str $price"
if ($str=='sed -n'('expr $lineNum+1'p)' testcase.txt')
then
x=$((x+1))
fi
y=$((y+1))
end
lineNum=$((lineNum+2))
end
echo $x/$y

Your script appears to be a mixture of tcsh and bash syntax.
As Mark's answer says, the then keyword has to be on the same line as the if (unless you use a backslash to splice two lines, but there's not much point in doing that).
For a variable assignment, the set keyword is not optional; this:
str="$str 1"
is a syntax error in csh/tcsh (it will probably look for a command whose name starts with "str=".) Write that as:
set str = "$str 1"
Note that you can optionally have spaces around the = in a set. tcsh's syntax is a bit messed up:
set foo=bar # ok
set foo = bar # ok
set foo= bar # ok
set foo =bar # error: "Variable name must begin with a letter."
The x=$((x+1)) syntax is specific to bash and related shells. tcsh uses # for arithmetic assignments:
set x = 42
# x ++ # sets $x to 43
# x = $x * 2 # sets $x to 86
If you have a choice, I suggest writing your script to use bash rather than tcsh (you're about halfway there already). Its syntax is much more regular.
The classic rant about csh/tcsh programming can be found here.

You are missing the end statement correspoding to the first while.
You are also using fi instead of endif.
The "then" keywords need to be on the same line as the "if" they belong to.

Related

storing current path in variable and reusing it

I know similar questions have already been asked, but somehow I am unable to figure out the mistake in my code.
I'm making a .bat file with the following code
echo off
echo %cd%
set curr_directory = "%cd%"
echo $curr_directory
pause
OUTPUT is :
C:\Users\MyDesktop>echo off
C:\Users\MyDesktop>
$curr_directory
Press any key to continue . . .
So what I dont get is why the value of variable curr_directory is not being printed.
What i eventually want to do is use the variable to change the directory something like this: cd $curr_directory
Thanks
I don't know where to start. EVERYTHING about your code is wrong. This should work:
#echo off
echo %cd%
set curr_directory=%cd%
echo %curr_directory%
pause
In batch you access variables via %var% and not $var. Further, DO NOT PUT SPACES behind =. SET x=123 will store 123 in x but SET x= 123 will store _123 (_ means space) in x.
EDIT: As SomethingDark stated, the first line should be #echo off except you actually want the message echo off to be printed. And yes, SET x = 123 means %x % is 123
use %curr_directory% instead of $curr_directory
Avoid spaces inbetween like the below one
"set curr_directory = %cd%"
below should work
echo off
echo %cd%
set curr_directory=%cd%
echo curr_directory is %curr_directory%
pause

table==1 was unexpected at this time batch file

I am trying to apply multiple SQL scripts to an Ingres database (using a vnode setup). The testing phase will require it done to four databases. Trying to nip this annoyance in the bud I've started a batch file but receive the error above.
Many of the solutions found suggest that the batch file will evaluate everything within a block when it starts but I cannot see the forest for the trees. I have a suspicion that the parts in :1ST and :2ND are causing the problems but they need to be done.
SQL, Batch and command window output are below
UPDATE core SET sysflag='O'
#ECHO off
SET VN1=dave
SET DB1=dbtest1
SET DB2=dbtest2
SET SQL1=open.sql
SET SQL2=open.sql
:MENU
CLS
ECHO 1 - Leave
ECHO 2 - Database1
ECHO 3 - Database2
SET /P M=Choose then press ENTER:
IF "%M%"=="1" GOTO EOF
IF "%M%"=="2" GOTO 1ST
IF "%M%"=="3" GOTO 2ND
GOTO MENU
:1ST
SET DATABASE=%VN1%::%DB1%
GOTO RUNSQL
:2ND
SET DATABASE=%VN1%::%DB2%
GOTO RUNSQL
:RUNSQL
ECHO Applying SQLs to %DATABASE%
SQL %DATABASE% < %SQL1% > log_%SQL1%.txt
PAUSE
SQL %DATABASE% < %SQL2% > log_%SQL2%.txt
PAUSE
GOTO MENU
:EOF
C:\Users\me\BUILD>IF UPDATE core SET sysflag='O'==1 GOTO EOF
You are expecting the value of %M% to have 1, 2, or 3. But somehow the value is UPDATE core. The IF statement fails because there is a space in the middle of the left value. Token delimiters like space must be escaped, or the entire string on each side should be quoted. You could change your statement to IF "%M%"=="1" GOTO EOF to eliminate the error, but it still will not give the results you want.
The SET /P statement reads the value from stdin. I assume you have not typed the value UPDATE core, but instead your input was either redirected or piped. You are feeding your script the wrong value.
You should add error handling so that the code does not fall through to :1ST if the input is not 1, 2, or 3.
You can explicitly redirect input to the console for your SET /P statement. That way it will ignore the redirected input or piped input that was provided for the batch script.
<con: SET /P "M=Choose then press ENTER: "
But something seems wrong with your whole design. If you are piping or redirecting input for the script, then it doesn't make sense to present an interactive menu of choices in a loop. What happens if the user never presses 1 to quit? Eventually the piped or redirected input will be exhausted, and then you have problems.

Windows Batch loop all variables with findstr

In my Windows batch file I have a various amount of variables. Lets say I have the following variables:
set varTest1=test1
set varTest2=test2
set otherVar=variable500
set varS=string
set yetAnotherVar=foo
They do really make no sense buts thats not the point. I am looking for a method that prints out all values of variables that start with var:
So when I run my batch with a certain help parameter it should print out all three variables starting with var and its value.
The output could look like this:
These are the available variables:
varTest1 : test1
varTest2 : test2
varS : string
I created the following for reading the parameter:
IF "%1" == "" (
echo No help parameter was set. Program will exit. ) ELSE (
IF "%1" == "help" (
call :showAllAvailableVars ) ELSE (
echo Do something else))
Now I would have my method
:showAllAvailableVars
I think the solution could be something with the findstr method but I could not figure it out how to do that because findstr is mainly for files and not for searching through own program variables.
Create array instead of different variables. Like,
set var[0]=test1
set var[1]=test2
set var[2]=string
then in your 'showAllAvailableVars' function do this
for /L %%i in (1,1,%n%) do echo !var[%%i]!
You could use set var to print all variables which begins with var.
See also set /?

batch file test error level

I'm trying to conditionally run an exe from a batch file conditionally upon another exe executing successfully.
I've tried a few different combinations of IF and ERRORLEVEL but none seem to work
"..\..\..\TeamBuildTypes\Current Branch\DatabaseUpdate.exe" -s localhost\sql2008r2
IF %ERRORLEVEL% 1(
"..\..\..\TeamBuildTypes\Current Branch\DatabaseUpdate.exe" -s localhost\sql2008
)
Pause
Gives me the error
1( was unexpected at this time.
Where am I going wrong here?
IF ERRORLEVEL ... is a special syntax supported since the DOS days, the %ERRORLEVEL% variable support was added in WinNT.
The original syntax is used like this:
call someapp.exe
if errorlevel 1 goto handleerror1orhigher
echo succuess...
To use the variable, use the normal IF syntax: if %errorlevel%==0 echo success...
Note that %errorlevel% stops working if someone does set errorlevel=foo and it might not get updated for internal cmd.exe commands.
An alternative solution is to use &&:
call someapp.exe && (echo success) || (echo error!)
There are (at least) two known cases where errorlevel is broken and you must use || instead:
RD/RMDir
> file redirection
Negative errorlevels can create problem. Try something like this:
IF '%ERRORLEVEL%'=='0' GOTO OK
Never use parenthesis to enclose any variables.
Parentheses are a block construct that will break DO and IF blocks and other things.
Instead use safe plain characters like "X" to enclose variables
E.g. To test for ERRORLEVEL of ONLY 0 use ...
IF X%ERRORLEVEL%X == X0X Echo or GOTO etc ...
It is safer this way as many special characters have special meanings and will break more complex code without any warning and take hours to debug. I know, this trap has befallen me whenever I forget my own advice.

capturing CMD batch file parameter list; write to file for later processing

I have written a batch file that is launched as a post processing utility by a program. The batch file reads ~24 parameters supplied by the calling program, stores them into variables, and then writes them to various text files.
Since the max input variable in CMD is %9, it's necessary to use the 'shift' command to repeatedly read and store these individually to named variables. Because the program outputs several similar batch files, the result is opening several CMD windows sequentially, assigning variables and writing data files. This ties up the calling program for too long.
It occurs to me that I could free up the calling program much faster if maybe there's a way to write a very simple batch file that can write all the command parameters to a text file, where I can process them later. Basically, just grab the parameter list, write it and done.
Q: Is there some way to treat an entire series of parameter data as one big text string and write it to one big variable... and then echo the whole big thing to one text file? Then later read the string into %n variables when there's no program waiting to resume?
Parameter list is something like 25 - 30 words, less than 200 characters.
Sample parameter list:
"First Name" "Lastname" "123 Steet Name Way" "Cityname" ST 12345 1004968 06/01/2010 "Firstname+Lastname" 101738 "On Account" 20.67 xy-1z 1 8.95 3.00 1.39 0 0 239 8.95
Items in quotes are processed as string variables. List is space delimited.
Any suggestions?
echo %* 1>args.txt
%* references all arguments: %1 %2 %3...
It also works with subroutines.
call :test 1 2 3
goto :eof
:test
echo 1: %1
echo 2: %2
echo 3: %3
echo *: %*
exit /b
output:
1: 1
2: 2
3: 3
*: 1 2 3
See the following website for more information:
http://ss64.com/nt/syntax-args.html
Interesting Post. It sparked my interest.
I too am needing something that could accept parameters and although this probably isn't useful to you now I thought it might be useful at some later date.
My solution is less simple - because there just isn't an elegant way to do it.
Basically, in this example the "-" can be used to identify a parameter, and the next space is assumed to be set to a value.
Legal Stuff:
So this is all my code and I don't really care how or where you choose to use it. No need to cite me it's just an example anyway.
Like this:
Microsoft Batch:Begin Copy below and save as filename.bat
#ECHO OFF
REM USAGE: this-batch-name.bat -BUILD "1.2.3 build 405" -JOB "Running This Job" -run RUN_FUNCTION
SET __CURRENT_WORKING_DIRECTORY__=%~dp1
ECHO.__CURRENT_WORKING_DIRECTORY__=%__CURRENT_WORKING_DIRECTORY__%
REM # Clear Previous Variables
SET PACKAGING_BUILD_NUMBER=
SET PACKAGING_JOB_NAME=
SET GO_DEEPER=
SET RUN_COMMAND=
REM ## In order to read variables set while in a "FOR" loop
REM ## you have to set the 'ENABLEDELAYEDEXPANSION' with 'SETLOCAL'.
SETLOCAL ENABLEEXTENSIONS
SETLOCAL ENABLEDELAYEDEXPANSION
REM ## Capture Command line parameters here with a %*
FOR %%A IN (%*) DO (
REM ## If we found something with a '-' in previous pass run GO_DEEPER will be defined and thus set to the command line argument.
IF DEFINED GO_DEEPER (
REM ## When ENABLEDELAYEDEXPANSION is Set with setlocal command you have to use exclamation: i.e. '^!'
IF /I "-BUILD"=="!GO_DEEPER!" SET PACKAGING_BUILD_NUMBER=%%A
IF /I "-JOB"=="!GO_DEEPER!" SET PACKAGING_JOB_NAME=%%A
IF /I "-RUN"=="!GO_DEEPER!" SET RUN_COMMAND=%%A
SET SET GO_DEEPER=
)
IF /I "%%A" GEQ "-" (
REM ## Wow we found your command line argument that started with a '-' so set the GO_DEEPER Var
SET GO_DEEPER=%%A
) ELSE (
SET SET GO_DEEPER=
)
)
REM ## Time to grab the variables set while in delayed expansion mode
ENDLOCAL && SET PACKAGING_BUILD_NUMBER=%PACKAGING_BUILD_NUMBER% && SET PACKAGING_JOB_NAME=%PACKAGING_JOB_NAME% && SET RUN_COMMAND=%RUN_COMMAND%
REM ## Sucks, but you have to clear the '"' and "'" if it exists.
IF DEFINED RUN_COMMAND (
SET RUN_COMMAND=%RUN_COMMAND:"=%
SET RUN_COMMAND=%RUN_COMMAND:'=%
)
IF DEFINED PACKAGING_JOB_NAME (
SET PACKAGING_JOB_NAME=%PACKAGING_JOB_NAME:"=%
SET PACKAGING_JOB_NAME=%PACKAGING_JOB_NAME:'=%
)
IF DEFINED PACKAGING_BUILD_NUMBER (
SET PACKAGING_BUILD_NUMBER=%PACKAGING_BUILD_NUMBER:"=%
SET PACKAGING_BUILD_NUMBER=%PACKAGING_BUILD_NUMBER:'=%
)
REM ## Now we can try to run the command function if the -run was used...
IF DEFINED RUN_COMMAND (
CALL:--%RUN_COMMAND% "'%PACKAGING_JOB_NAME%'","'%PACKAGING_BUILD_NUMBER%'"
) ELSE (
ECHO Try running:
ECHO %0 -BUILD "1.2.3 build 405" -JOB "Running This Job" -run RUN_FUNCTION
)
GOTO DONE
:--RUN_FUNCTION
ECHO running... %~0
SET VARPASSED1=%~1
SET VARPASSED2=%~2
IF DEFINED VARPASSED1 ECHO VARPASSED1 was %VARPASSED1%
IF DEFINED VARPASSED2 ECHO VARPASSED2 was %VARPASSED2%
ECHO Add your code to process here...
GOTO:EOF
:DONE
ECHO We got the following results...
IF DEFINED PACKAGING_JOB_NAME ECHO PACKAGING_JOB_NAME=%PACKAGING_JOB_NAME%
IF DEFINED PACKAGING_BUILD_NUMBER ECHO PACKAGING_BUILD_NUMBER=%PACKAGING_BUILD_NUMBER%
IF DEFINED RUN_COMMAND ECHO RUN_COMMAND=%RUN_COMMAND%
</pre> </code>
Microsoft Batch END Copy
RESULTS:
__CURRENT_WORKING_DIRECTORY__=C:\dev\a\win\sysprep\
running... :--RUN_FUNCTION
VARPASSED1 was "'Running...'"
VARPASSED2 was "'This...'"
We got the following results...
PACKAGING_JOB_NAME="Running This Job"
PACKAGING_BUILD_NUMBER="1.2.3 build 405"
RUN_COMMAND=RUN_FUNCTION