Conditional statement not working as expected - linux

I am using Konsole on kubuntu 14.04.
I want to take arguments to this shell-script, and pass it to a command. The code is basically an infinite loop, and I want one of the arguments to the inner command to be increased once every 3 iterations of the loop. Ignoring the actual details, here's a gist of my code:
#!/bin/bash
ct=0
begin=$1
while :
do
echo "give: $begin as argument to the command"
#actual command
ct=$((ct+1))
if [ $ct%3==0 ]; then
begin=$(($begin+1))
fi
done
I am expecting the begin variable to be increased every 3 iterations, but it is increasing in the every iteration of the loop. What am I doing wrong?

You want to test with
if [ $(expr $cr % 3) = 0 ]; then ...
because this
[ $ct%3==0 ]
tests whether the string $ct%3==0, after parameter substitution, is not empty. A good way for understanding this is reading the manual for test and look at the semantics when it is given 1, 2, 3 or more arguments. In your original script, it only sees one argument, in mine it sees three. White space is very important in the shell. :-)

In BASH you can completely utilize ((...)) and refactor your script like this:
#!/bin/bash
ct=0
begin="$1"
while :
do
echo "give: $begin as argument to the command"
#actual command
(( ct++ % 3 == 0)) && (( begin++ ))
done

Related

creating multiple user named and numbered files without loop from bash

Totally new in bash programming and got a problem like this:
N empty files should be created. The file sum N and also the file name should be given from users via command line.
no loop and getopts should be used.
I've tried something like this which i found from google but it doesn't works. I got confused between linux and windows bash scripts. Hope someone can help me with the problem. Thank you!
#!/bin/bash
echo $N
:start
if [ $N > 0 ]
then
touch xyzfile_$N
$N = $N - 1
pause
goto start
else
then
echo "no data will be created"
fi
The command line and the result should be (for example if N=7) look like this:
command line:
./createfiles -n filename 7
expected result:
filename_1,filename_2,filename_3...filename_7
You can do this using a recursive shell function:
fn() {
# add some sanity checks to check parameters
touch "$1_${2}"
(($2 > 1)) && fn "$1" $(($2 - 1))
}
This part is a recursive call:
(($2 > 1)) && fn "$1" $(($2 - 1))
Where it basically calls itself by decrementing 1 from 2nd argument as long as $2 is greater than 1.
Then just call it as:
fn filename 7
It will create 7 files as:
filename_1 filename_2 filename_3 filename_4 filename_5 filename_6 filename_7
I ended up the question with a for-loop like this:
createfile() {
name="$1"
num="$2"
for((i=1;i<=num;i++))
do
touch "$1_${i}"
done
}
createfile $1 ${2}
It works great actually. And now I tried to solve the problem with getopts and it seems a function call doesn't work in the case option

Bash script : $x=$x+2 is not getting recognised

When I am executing the below script, I am getting the following error :-
The script executes infintely and below line is printed everytime.
"line 9: 1=1+2: command not found". Why?
#!/bin/bash
echo "Script 1 - Linux Scripting Book"
x=1
while [ $x -le 45 ]
do
echo x : $x
$x=$x+2
done
echo "End Of Script 1"
exit 0
Also if I change the $x=$x+2 to x+$x+2 then also I am getting the below error.
line 6: [: 1+2: integer expression expected
Same script when executed like this runs fine.
#!/bin/bash
echo "Script 1 - Linux Scripting Book"
x=1
while [ $x -le 45 ]
do
echo x : $x
let x=x+2
done
echo "End Of Script 1"
exit 0
You get line 9: 1=1+2: command not found because 1=1+2 is what $x=$x+2 is expanded into.
Use expr or let or ((...)) for integer calculations and bc for floating point:
let x=x+2
((x=x+2)) #same as above
((x+=2)) #same
((x++)) #if adding just one
((++x)) #if adding just one
x=$((x+2))
x=`expr $x + 2` #space before and after +
x=$(echo $x+2|bc) #using bc
x=$(echo $x+2.1|bc) #bc also works with floating points (numbers with decimals)
Since this part of the question isn't cleared yet, and not fine to post in a comment, I add this partial answer:
x=1; for i in 1 2 3 ; do x=$x+2; echo $x; done
1+2
1+2+2
1+2+2+2
As a side note: Don't use exit 0 at the end of your script without a good reason. When the script is done, it exits by itself without your help. The exit status will be the exit status of the last command performed, in your case a simple echo, which will almost always succeed. In the rare cases it fails, you will probably without intention hide that failure.
If you source the script, the exit will throw you out of your running shell.
But you can rewrite your while loop like this:
x=0
while (($((x)) < 9))
do
echo x : $x
x=$x+2
done
echo $((x))
x : 0
x : 0+2
x : 0+2+2
x : 0+2+2+2
x : 0+2+2+2+2
10
Because that's not the Bourne shell syntax for setting a variable; it looks more like Perl or PHP. The $ is used for parameter expansion and is not part of the variable name. Variable assignment simply uses =, and let evaluates arithmetic expressions (much like $((expression))). Another syntax that should work is x=$((x+2)). Note that these arithmetic evaluations are a bash feature; standard unix shells might require use of external tools such as expr.

Syntax error near unexpected token `done' whis done written

I have a problem with the done.
It says I have some typo error but I can't figure what's wrong at all.
Here is the code:
#./bin/bash
until [$err == 0];
do
java -Xms512m -Xmx512m -cp lib/*:lib/uMad/*:mysql-connector-java-5.1.15-bin.jar:l2jfrozen-core.jar com.l2jfrozen.gameserver.GameServer
err=$?
sleep 5
done
Your shebang line is wrong. #./bin/bash will not execute bash.
It should read #!/bin/bash. You are probably using a shell other than bash to invoke this script.
Also, beware that the [$err == 0] line expands the value of $err, which is probably an empty string, unless it has been exported. If it's empty, this will result in an error, because Bash will be interpreting [ == 0].
The safest approach is this:
unset err
until [ "$err" == "0" ];
do
# etc...
done
From my experience when working with brackets and if loops, you need proper spacing and double, not single brackets. There needs to be space on each side of the double brackets with the exception of the semi-colon. Here is an example block:
#!/bin/bash
err=5
until [[ $err == 0 ]]; do
((err-=1));
echo -e "$err\n";
sleep 3
done
I do not see why the same would not apply to a do until loop.
You're probably aware but your heading has a period in it instead of a shebang.
#./bin/bash

Shell Scripting - How to mock some results based on an input?

I have a small scripts which verifies some conditions on a database server. I want to mock failures on all of those conditions to test the script, so I added the following line:
./print_results ${VAR1} ${VAR2} ... ${VARN}
If any of the variables has a value different than ZERO it because it failed.
so just for testing purpouses I added the line:
VAR1=1 ; VAR2=1 ; ... ; VARN=1
But I need to edit the file every time I want to replace the real results with the fake ones.
What's wrong with this?
[! -z $1 ] && [ "$1" == "Y"] && { echo "Debugging is ACTIVE" ; VAR1=1 ; ... ; VAR2=1 ; }
I want to have the VAR1..N = 1 after passing that line.
Thanks.
The problem is that [ is a command, but [! is not. It is probably cleaner to write your code:
test "{$1}" == Y && { echo "Debugging is ACTIVE"; VAR1=1 VAR2=1 ...; }
No need for semi-colons between the variable assignments, but they don't hurt.
This is one of the warts of sh. For some reason, it was thought to be a good idea to use the symbol [ for a command and pass it ] as an argument, trying to mimic braces in the language. Unfortunately, this leads to a great deal of confusion similar to that demonstrated in this question. It is far better to avoid [ completely and always spell it test. These two are functionally identical (except that the [ command must have ] as the final argument), and using test is much cleaner. (Would you expect test! to work?, or would you recognize that it needs to be written as ! test?)
Need a space between the "Y" and the ]. The non-zero test is pointless, but also requires a space between the [ and the !.
[ "$1" == "Y" ] && { echo "Debugging is ACTIVE" ; VAR1=1 ; ... ; VAR2=1 ; }
Also did you consider just writing this as an if...fi block?
bash provides a way to supply default values for parameters that aren't otherwise set. Presumably, your code has lines like
VAR1=$1
VAR2=$2
VAR3=$3
Replace them with
VAR1=${1-1}
VAR2=${2-1}
VAR3=${3-1}
If $1 is unset, for instance, VAR1 will be assigned the value of 1 instead of the value of $1.

Compare integer in bash, unary operator expected

The following code gives
[: -ge: unary operator expected
when
i=0
if [ $i -ge 2 ]
then
#some code
fi
why?
Your problem arises from the fact that $i has a blank value when your statement fails. Always quote your variables when performing comparisons if there is the slightest chance that one of them may be empty, e.g.:
if [ "$i" -ge 2 ] ; then
...
fi
This is because of how the shell treats variables. Assume the original example,
if [ $i -ge 2 ] ; then ...
The first thing that the shell does when executing that particular line of code is substitute the value of $i, just like your favorite editor's search & replace function would. So assume that $i is empty or, even more illustrative, assume that $i is a bunch of spaces! The shell will replace $i as follows:
if [ -ge 2 ] ; then ...
Now that variable substitutions are done, the shell proceeds with the comparison and.... fails because it cannot see anything intelligible to the left of -gt. However, quoting $i:
if [ "$i" -ge 2 ] ; then ...
becomes:
if [ " " -ge 2 ] ; then ...
The shell now sees the double-quotes, and knows that you are actually comparing four blanks to 2 and will skip the if.
You also have the option of specifying a default value for $i if $i is blank, as follows:
if [ "${i:-0}" -ge 2 ] ; then ...
This will substitute the value 0 instead of $i is $i is undefined. I still maintain the quotes because, again, if $i is a bunch of blanks then it does not count as undefined, it will not be replaced with 0, and you will run into the problem once again.
Please read this when you have the time. The shell is treated like a black box by many, but it operates with very few and very simple rules - once you are aware of what those rules are (one of them being how variables work in the shell, as explained above) the shell will have no more secrets for you.
Judging from the error message the value of i was the empty string when you executed it, not 0.
I need to add my 5 cents. I see everybody use [ or [[, but it worth to mention that they are not part of if syntax.
For arithmetic comparisons, use ((...)) instead.
((...)) is an arithmetic command, which returns an exit status of 0 if
the expression is nonzero, or 1 if the expression is zero. Also used
as a synonym for "let", if side effects (assignments) are needed.
See: ArithmeticExpression
Your piece of script works just great. Are you sure you are not assigning anything else before the if to "i"?
A common mistake is also not to leave a space after and before the square brackets.

Resources