How can I check if and greater than condition in linux? - linux

If tag_len is greater than 18 or tag_len is 19 and the tag is not ends with "A",
I want to cut the tag to length 18.
I tried several options but that is not working correctly.
Could you let me now how I can do this?
#officail daily release TAG check
official_tag_len=18
export tag_len=`expr length $TAG`
if (($tag_len > $official_tag_len))
then
echo "$TAG length is greater than $official_tag_len"
if (($tag_len == ($official_tag_len+1))) && (($TAG == *A))
then
echo $TAG is an AM daily tag
else
echo $TAG is a temporary tag. reset to daily tag
export TAG=$($TAG:0:$official_tag_len)
fi
fi
UPDATE
the final error message is
e7e10_preqe2:0:18: command not found
I edit the code "export TAG=$($TAG:0:$official_tag_len)"
referring to Extract substring in Bash
and one more thing,
at first I wrote [[ instead of (( in if condition but command not found error occurs in [[ line.
Usually, I used [ ] expression in if condition.
Are there any exceptional cases?

The question setup is a bit difficult to understand, but I think this runs the way you want on bash. You didn't specify interpreter for the question..
I have taken liberty to take the "TAG" as input parameter (TAG=$1, and calculate it's length using command wc).
I have replaced all the if statements to use square brackets, and also use keyword -gt (greater than) for comparison (use lt for <, and eq for ==). These are meant to be used for numerical comparison.
#!/bin/bash
#officail daily release TAG check
TAG=$1
tag_len=`echo $TAG | wc -c`
official_tag_len=18
echo "input $tag, length: $tag_len"
if [[ $tag_len -gt $official_tag_len ]];
then
echo "$TAG length is greater than $official_tag_len"
if [[ $tag_len -eq $(($official_tag_len+1)) ]] && [[ $TAG == *A ]];
then
echo $TAG is an AM daily tag
else
echo $TAG is a temporary tag. reset to daily tag
export TAG=${TAG:0:official_tag_len}
echo "new tag: [$TAG]"
fi
fi

Related

bash: convert string to int & if int > #

I would like to have a bash script that checks if a file has more than # amount of lines but i have not yet got it working right and I'm not so sure on how to do it.
I've never used bash before.
right now i use: linesStr=$(cat log | wc -l) to get the amount of lines in the file (expect it to be a string). when echo'ing it gives me the number 30 which is correct.
but since its most likely a string it doesnt do the if-statement, so i need to have linesStr converted into a int called linesInt.
I also have the feeling the if-statement itself is not done correctly either.
#!/bin/bash
linesStr=$(cat log | wc -l)
echo $linesStr
if [$linesStr > 29]
then echo "log file is bigger than 29 lines"
#sed -i 1d log
fi
I would appreciate if anyone can give me a simple beginners solution.
No need for cat.
Lack of spaces around [ and ].
Use a numeric comparison operator instead of the redirect operator.
Here is a working script.
#!/bin/bash
linesStr=$( wc -l < log )
if [[ "$linesStr" -gt "29" ]]; then
echo Foo
fi
your if block of code is wrong if [$linesStr > 29] there should be a space after [ and before ]
#!/bin/bash
linesStr=$(wc -l < log )
echo $linesStr
if [[ $lineStr -gt 29 ]];then
echo "log file is bigger than 29 lines"
fi
it is advisable that you always use [[ ]] with an if statement rather than using [ ]. Whenever you want to compare integers dont use > or <, use -gt -ge -lt -le. And if you want to do any form of mathematical comparison it is advisable that you use (( )).
(( lineStr > 29 )) && {
# do stuff
}
you should also note that you don't need the bash comparison operators or getting the value of a variable with $ when using (( ))
There are no string or integer types to convert. The problem is that you're using the wrong comparison operator. For numeric comparison use if [ $linesStr -gt 29 ]. Read man bash section CONDITIONAL EXPRESSIONS for available operators.
(( $(wc -l < log) > 29 )) && echo too long

Convert bash script using regexes to sh

I'm really struggling with writing a Bourne shell script. Basically, I have three input formats for a variable called "ref" that I'm trying to detect:
ref="refs/head/.*" (i.e. begins with "refs/head/" I'm interested in the bit at the end, after the slash)
ref="refs/tags/.*" (i.e. begins with "refs/tags/" I'm interested in the bit at the end, after the slash)
everything else (i.e. ignore everything that doesn't begin with either "refs/head/" or "refs/tags/")
For example,
If ref="refs/head/master", set TAG="master"
If ref="refs/tags/0.2.4", set TAG="0.2.4"
For everything else, set TAG=""
Now I wrote something in bash shell, but I'm really struggling to convert it to Bourne (#!/bin/sh):
#!/bin/bash
#
#This works!
#
TAG=""
re='^refs/head/.*' #regex: begins with refs/head/, ends with anything
re2='^refs/tags/.*' #regex: begins with refs/tags/, ends with anything
if [[ $ref =~ $re ]]; then
#do nothing - OK
true #NOP
else
#check if it's a tag update
if [[ $ref =~ $re2 ]]; then
TAG=${$ref##*/} #looks worse that it is: http://stackoverflow.com/questions/3162385/how-to-split-a-string-in-shell-and-get-the-last-field
fi
exit 0
fi
echo $TAG
It took me ages to a) write this program and b) find out why my program was going nuts - turned out I need #!/bin/sh and not #!/bin/bash
How can I convert this to sh? Maybe someone else has a more elegant solution to my regex gymnastics?
Update:
Thanks for the answers sofar (especially #gboffi). I think I'm almost there.
All I need now is to know if $TAG comes from "refs/head/", "refs/tags/" or neither. I tried to modify some of the answers, but really struggling with sh. I'll need to go away and learn more about sh from first principles instead of trying to hack it.
Update 2:
So after a night's sleep, I figured it out in about 20 minutes. Here is my solution:
#!/bin/sh
ref="refs/asdf/master"
TAG=""
TAG="${ref#refs/heads/}"
if [ "$ref" != "${ref#refs/heads/}" ]; then
echo "heads"
echo $TAG
else
TAG="${ref#refs/tags/}"
if [ "$ref" != "${ref#refs/tags/}" ]; then
echo "heads"
echo $TAG
else
TAG=""
fi
fi
echo "--->$TAG"
I'm sure there's a much more elegant solution; but I just don't have the time!
Here it is a function, defined in dash (the linux version of sh)
% dash
$ tag() {
> TAG=""
> [ "$1" != "${1#refs/head/}" ] && TAG="${1#refs/head/}"
> [ "$1" != "${1#refs/tags/}" ] && TAG="${1#refs/tags/}"
> echo "$TAG"
>}
$ tag poldo
$ tag refs/head/poldo
poldo
$ tag refs/tags/pippo
pippo
$ tag to093u0refs/head/poldo
$exit
%
The most idiomatic way to handle this is with a case statement and pattern matching:
#!/bin/sh
case $ref in
refs/head/*) true ;; # original behavior: no output, success
refs/tags/*) printf '%s\n' "${ref##*/}" ;; # original behavior: emit output
*) false # exit with an error # original code didn't specify behavior
esac
The reason I'm exiting with an error for the case where neither refs/head/* or refs/tags/* matches is that if you wanted to exit with success in that case, you could omit the refs/head/* test entirely.
You can use rev-parse for this, here are some examples from one of my
repositories. Notice the last one produces no output, as desired.
$ git rev-parse --abbrev-ref refs/heads/master
master
$ git rev-parse --abbrev-ref refs/tags/5
5
$ git rev-parse --abbrev-ref #^
Having read your description of the desired function it seems that it boils down to this:
check the input argument. If it starts with refs/head or refs/master, proceed, else stop.
take the terminal piece of information and set the variable TAG to it.
thus, assuming your input is in the variable REF,
TAG=""
echo $REF | egrep -q 'refs/head|refs/master'
if [ $? -eq 0 ]
then
TAG=`echo $REF | sed "s/.*\///"`
fi
ought to do it.
(Side note for shell heads: is basename a better solution than sed in this particular case?)

Why does [$value -lt 10] in shell result in command not found? [duplicate]

This question already has answers here:
"Command not found" when attempting integer equality in bash
(3 answers)
Closed 8 years ago.
Output 1:
Enter your value: 12
./testscript.sh: line 4: 12: command not found
Your value is more than 10
Output 2:
Enter your value: 5
./testscript.sh: line 4: 12: command not found
Your value is more than 10
I need to know what is wrong. My Linux test is just tomorrow:(
#!/bin/bash
echo -n "Enter your value: "
read value
if [$value -lt 10]
then
echo "Your value is less than 10"
else
echo "Your value is more than 10"
fi
your if statement should be as below. A space before ']' and space after '['
if [ $value -lt 10 ]
EDIT
As per the comments
you can always add optional ; at the end of the line. The below script would work fine.
a=20;
if [ $a -gt 10 ];
then
echo "true";
else
echo "false";
fi
you need to put your condition in the [ condition ]. The below one does not work.
( condition )
It would say command not found. As '(' is not command. where as '[' is a command in order to check a condition
And the more appropriate way is to use [[ ]] over [ ] when in Bash since you can avoid word splitting and pathname expansion with it. Other conditions can be added as well:
if [[ ! $value =~ [0-9]+ ]]; then
echo "Invalid input."
elif [[ value -lt 10 ]]; then
echo "Your value is less than 10."
elif [[ value -eq 10 ]]; then
echo "Your value is 10."
else
echo "Your value is more than 10."
fi
To throw yet another option into the mix: bash has (( ... )) -- arithmetic conditions:
if (( $value < 10 )); then ...
http://www.gnu.org/software/bash/manual/bashref.html#Conditional-Constructs
One thing you can do in bash with arithmetic expressions is to drop the $.
if (( value < 10 )); then
This is documented a bit obscurely in Shell arithmetic: "Within an expression, shell variables may also be referenced by name without using the parameter expansion syntax."
This may appeal to aficionados of C-like languages, but it's a bit out of step with the rest of the languages, and it doesn't apply to all variables (such as special paramaters ($#)
and array elements (${foo[3]})).

Need to validate the length of a variable and perform an action accordingly in unix

We have a variable with a value in it. My requirement is if the length of the variable is greater than 0(zero) do something else do another thing
Step1: I have a variable with some value say
abc="asdfg"
Step2: Determine the length of the variable
xyz=`echo ${#abc}`
Step3: Now I use a If loop to determine if the variable has value greater than 0
if [[$xyz -gt 0]]; then
echo "success"
else
echo "fail"
fi
I am having a problem at step 3. it does not give me a success message. need assistance
You can check if a variable is not zero length with -n
if [ -n $abc ]; then
echo "success"
fi
if [[$xyz -gt 0]]; then
should be:
if [[ $xyz -gt 0 ]]; then
You need spaces between the brackets and parameters.
You can do it easily like this:
VAR=""
if [ "$VAR" ]; then echo Full; fi
VAR="a"
if [ "$VAR" ]; then echo Full; fi
Full
You are missing some spaces around your square brackets.
A short and fast solution to do this is to use ${#var} directly in an if-test:
if (( ${#abc} )); then
# ...
fi
This removes the unnecessary command-substituion that you have there and tests directly on the length. If the length is zero then the test fails.

How do I deal with empty user input in a Bash script?

When the script asks me for input, I get an error if I just press Return without typing in anything. How do I fix this?
Here's the script:
#!/bin/bash
SUM=0
NUM=0
while true
do echo -n "Pruefungspunkte eingeben ('q' zum Beenden): "
read SCORE
if test "$SCORE" == "q"
then echo "Durchschnittspunktzahl: $AVERAGE."
break
else SUM=`expr $SUM + $SCORE`
NUM=`expr $NUM + 1`
AVERAGE=`expr $SUM / $NUM`
fi
done
How about using good bash practices?
#!/bin/bash
sum=0
num=0
while true; do
read -erp "Pruefungspunkte eingeben ('q' zum Beenden): " score
if [[ $score = q ]]; then
echo "Durchschnittspunktzahl: $average."
break
elif [[ $score =~ ^-?[[:digit:]]+$ ]]; then
((sum+=10#$score))
((++num))
((average=sum/num))
else
echo "Bad number"
fi
done
Good practice:
don't use capitalized variable names
use the [[ builtin instead of the test builtin
don't use backticks, use (( to invoke shell arithmetic
to make sure the user inputs a number, check that a number was really entered. The line
elif [[ $score =~ ^-?[[:digit:]]+$ ]]; then
just does that (see regular expressions). Incidentally it completely solves your original problem, since an empty input will not pass through this test
to prevent problems if a user enters 09 instead of 9, force bash to interpret the input in radix 10. That's why I'm using (10#$score) instead of just score.
Use read with the -p (prompt) option, instead of the clumsy combo echo -n / read
This version is much more robust and well-written than yours. Yet, it still has problems:
will break if user needs large numbers
as shell arithmetic is used, only integers can be used. Moreover, the average given by this program is rounded: if you want the average of 1 and 2 you'll have 1.
To fix both problems, you'll probably want to use bc or dc. But that will be the purpose of another question. Or not.
Initialise $SCORE beforehand or handle empty input like you do in q case.
[[ -z "$SCORE" ]] && echo "\$SCORE is zero, e.g. \"\""
This will test if the variable SCORE is empty string.
You should also set AVERAGE=0 at the beginning.

Resources