how to check digit is even or not in linux shell? - linux

i tried
pancmite#atlas:~$ test ($LSD / 2) -eq 0
bash: syntax error near unexpected token `$LSD'
pancmite#atlas:~$ test $LSD / 2 -eq 0
bash: test: too many arguments
pancmite#atlas:~$ test $number -lt $LSD
bash: test: -lt: unary operator expected
i want one line command.

expr $LSD % 2
or alternatively:
$((LSD % 2))
A returned value of 1 is odd and 0 is even. So you could try this as a test:
LSD=5
echo $((LSD % 2))
and you should get a returned value of 1.

Related

"Attempted assignment to a non-variable" in bash

I'm new to Bash and I've been having issues with creating a script. What this script does is take numbers and add them to a total. However, I can't get total to work.It constantly claims that total is a non-variable despite it being assigned earlier in the program.
error message (8 is an example number being entered)
./adder: line 16: 0 = 0 + 8: attempted assignment to non-variable (error token is "= 0 + 8")
#!/bin/bash
clear
total=0
count=0
while [[ $choice != 0 ]]; do
echo Please enter a number or 0 to quit
read choice
if [[ $choice != 0 ]];
then
$(($total = $total + $choice))
$(($count = $count + 1))
echo Total is $total
echo
echo Total is derived from $count numbers
fi
done
exit 0
Get rid of some of the dollar signs in front of the variable names. They're optional inside of an arithmetic context, which is what ((...)) is. On the left-hand side of an assignment they're not just optional, they're forbidden, because = needs the variable name on the left rather than its value.
Also $((...)) should be plain ((...)) without the leading dollar sign. The dollar sign will capture the result of the expression and try to run it as a command. It'll try to run a command named 0 or 5 or whatever the computed value is.
You can write:
((total = $total + $choice))
((count = $count + 1))
or:
((total = total + choice))
((count = count + 1))
or even:
((total += choice))
((count += 1))

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.

Bash interpreting increment operation as command

I'm trying to batch modify some images using a bash script, and to print out the progress. It looks to me like bash is interpreting the increment to counter as a command and is giving the following error:
augment_data.sh: line 20: 0: command not found
Here is the code:
for file in *.jpg
do
convert $file -rotate 90 rotated_"$file"
((counter++))
if $((counter % 10 == 0)); then
echo "Rotated $counter files out of $num_files"
fi
done
with line 20 being the one with the counter increment operation.
How can I fix this so that I don't get the error message?
In an arithmetic substitution, the result of an arithmetic operation is substituted in the position of the operation itself.
In this case, $(( 1 == 0 )) has an arithmetic result of 0, and $(( 1 == 1 )) has a result of 1.
Thus, if you use $(( ... )), then this 0 or 1 is substituted in that position, and so gets run as a command. Since you don't have commands named 0 or 1 (probably), either of these will result in a command not found error.
If you use (( ... )), then the arithmetic result directly sets return value, but no expansion takes place.

How to compare variables in bash

I'm begginer in linux console; I want to create if statement with integer variables
if[$x= [$#-2]]
But console receive if can't find this statment if[1 = [5-2]]
Please help me and correct my statement.
You need Arithmetic Expansion: $((expression))
if [ $x = $(($# - 2)) ]; then
# ^ ^ ^ ^ ^ spaces are mandatory
To start $# is the number of parameters passed to the bash script
./bash_script 1 2 3
$# auto-magically populates to 3. I hope you know this already.
#!/bin/bash
x=1
#If you are trying to compare `$x` with the value of the expression `$# - 2` below is how you do it :
if (( $x == $# - 2 ))
then
echo "Some Message"
fi
#If you are trying to check the assignment to `$x was successful below is how you do it :
if (( x = $# - 2 ))
then
echo "Some Message"
fi
The second condition is almost always true, but the first can be false.
Below are the results of my test runs :
#Here the both ifs returned true
sjsam#WorkBox ~/test
$ ./testmath1 1 2 3
Some Message
Some Message
#Here the first if returned false because we passed 4 parameters
sjsam#WorkBox ~/test
$ ./testmath1 1 2 3 4
Some Message

Require efficient and probably one to two liner solution to replace space

Having following bash scripts to find index of the command from command list
#!/bin/bash
cmdlist="cmd1,cmd2,cmd,cmd24,cmd25,cmd4,cmd10,cmd9,cmd000001,cmdxyz"
cmdlist="${cmdlist//,/ }" #To Replace , with space in array list
cmdlist="${cmdlist//cmd/ }" #To get index of command
echo $cmdlist //Added for clarification
for a in $cmdlist
do
if [[ $a == *[^[:digit:]]* ]] || [[ $a -gt 50 ]]
then
printf "invalid command index : %s\n" $a
else
printf "command index : %s\n" $a
fi
done
As you can see how I extract command index from command list but it's failing (of course it fails) in some condition. So want make some validations as follows:
1) In list, if argument is cmd then it will skipped and not replace space instead cmd string because argument length must be greater then 3.
2) In list, if argument is cmd0001 then also skipped and not replace space instead cmd string because argument length must be less or equal 5 and greater then 3.
Following above validation I achieved by taking for..loop, taking temporary array then compare each argument and validate then store in temporary array and finally copy temporary array in original one.So this is too long procedure.
Any one have idea for batter solution?
Like
cmdlist="${cmdlist//cmd/ }" #To get index of command
command only replace space instead cmd in target argument if condition [[ length -gt 3 ]] && [[ length -le 5 ]] match.
Note: have already have solution using for..loop.
UPDATE: Added more detail for what i want
I got output this from script
command index : 1
command index : 2
command index : 24
command index : 25
command index : 4
command index : 10
command index : 9
command index : 000001
invalid command index : xyz
but i want this
command index : 1
command index : 2
invalid command index : cmd
command index : 24
command index : 25
command index : 4
command index : 10
command index : 9
command index : cmd000001
invalid command index : cmdxyz
So basically leave the argument which not in validation range and mark as invalid index(nothing to do not require to replace space in place of cmd string.)
More UPDATE: Again added more detail to clarify exactly what i want
Have added one echo statement before for..loop in my script ( see modified above script ) which give me output like this
1 2 24 25 4 10 9 000001 xyz
but i want
1 2 cmd 24 25 4 10 9 cmd000001 cmdxyz
means leave argument as it is if it violate validation like in my list third argument is cmd.It violate the condition becasue it's length not greater then 3.Now see last two argument in list cmd000001,cmdxyz It violate the condition because it's length greater then 5. Valid argument is one for which length must be greater then 3 && less or equal 5.
Hope this will clarify what i want.
Editing as per your update:
Get the values in an array and check within the loop if those meet the required criteria:
cmdlist="cmd1,cmd2,cmd,cmd24,cmd25,cmd4,cmd10,cmd9,cmd000001,cmdxyz"
IFS=, read -a arr <<< "$cmdlist"
for a in "${arr[#]}"
do
v="${a/cmd/}"
if ((v > 50)) || ((v <= 0))
then
printf "invalid command index : %s\n" $a
else
printf "command index : %s\n" $v
fi
done
For your input, it'd produce:
command index : 1
command index : 2
invalid command index : cmd
command index : 24
command index : 25
command index : 4
command index : 10
command index : 9
command index : 000001
invalid command index : cmdxyz
Old answer:
Instead of attempting to replace , with spaces and so on, read the string delimited by comma into an array. Manipulate the array to get one containing the desired strings.
$ IFS=, read -a arr <<< "$cmdlist"
$ foo=(${arr[#]/cmd/})
$ for i in "${foo[#]}"; do echo $i; done
1
2
24
25
4
10
9
000001
xyz
$
Checking...
for a in "${foo[#]}"
do
if [[ $a == *[^[:digit:]]* ]] || [[ $a -gt 50 ]]
then
printf "invalid command index : %s\n" $a
else
printf "command index : %s\n" $a
fi
done
produces:
command index : 1
command index : 2
command index : 24
command index : 25
command index : 4
command index : 10
command index : 9
command index : 000001
invalid command index : xyz
A note of caution: Numbers with leading zeros (as you have in your example) would be considered as octal and might produce unexpected results:
$ [[ 0024 -gt 22 ]] && echo greater || echo smaller
smaller

Resources