I'm stuck in something in my bash script, I have a string that composes of a repetitive sequence of 20s, e.g. 202020, there might be more or less 20s, e.g. 2020 or 2020202020, I want to create an if condition that if finds any strange number inside, e.g. 30 in 20203020, gives an error.
Any ideas?
this should do the test:
[[ "$var" =~ "^(20)+$" ]]
check this:
kent$ [[ "202" =~ "^(20)+$" ]] && echo "y" || echo "n"
n
kent$ [[ "20203" =~ "^(20)+$" ]] && echo "y" || echo "n"
n
kent$ [[ "20202002" =~ "^(20)+$" ]] && echo "y" || echo "n"
n
kent$ [[ "20202020" =~ "^(20)+$" ]] && echo "y" || echo "n"
y
how about this example, can you use it?
if [ "`echo "202020302020" | sed -e 's/20//g'`" ];
then echo "there is something";
fi
Extended patterns are a tiny bit more compact than regular expressions.
shopt -s extglob
if [[ $str = +(20) ]]; then
echo "twenties"
else
echo "mismatch"
fi
At some point, bash changed to treat all patterns in [[...]] expressions as extended patterns, so the shopt command may not be necessary.
Related
I need to check if the value c exists in an integer array, I'm aware of how to approach this using for loops and if statements:
for c in {1..100};do
sequence=(2 4 6 8 10 12 14 16)
for value in "${sequence[#]}";do
if [[ $value -eq $c ]];then #If c exists in sequence
flag=1
break
fi
done
done
But I don't want this, I tried something similar to this:
[[ ${sequence[*]} =~ $c ]]
But it didn't give me the desired results, I think it works only with string arrays, not integers.
How could I approach this?
Converting my comment to answer so that solution is easy to find for future visitors.
You may use this grep + printf solution:
grep -qFx "$c" <(printf '%s\n' "${sequence[#]}") && echo "found" || echo "nope"
The problem with this method [[ ${sequence[*]} =~ $c ]] is that if $c is 1, than it'll match all instances with 1. Try this approach, make your sequence a regex like this
re=${sequence[*]}
re=${re// /|}
$ echo $re
2|4|6|8|10|12|14|16
Testing
c=1
$ [[ $c =~ $re ]] && echo ok || echo fail
fail
c=11
$ [[ $c =~ $re ]] && echo ok || echo fail
fail
c=12
$ [[ $c =~ $re ]] && echo ok || echo fail
ok
Briefly,
I have a variable ($num) which contains random number(max.18), I need a case statement in shell (because along with checking number, I also have some alphabet conditions) which should validate the user input with the variable (must be less than $num).
Ex:
case $input in
...
1) ... ;;
2) ... ;;
...
so, here if I have only two conditions than I can write code like this, but my variable $num contains random number, how can I write case conditions which satisfies my below requirements.
If user inputs numbers like (1/3,3*1,3-2,2+1) it should not validate as a number
If user inputs numbers like (0001 or 01 or 000001) it should not validate as a number
The case condition should execute only if user inputs number between 1-$num no other number formats or symbols should not allowed.
Ex:
case $input in
[nN*]) ...
[aA*]) ...
...
*) if echo "$input" | egrep '^\-?[0-9]+$'; then
typeset -LZ num
num="$input"
if [ "$input" != "$num" ]; then
echo "$input not a valid number"
fi
else
echo "please choose proper choice option"
fi
;;
This code works but I want a normal case condition which should satisfy my requirements like if we have two or three options we can simply write the code but what if we have random options (which may decrease or increase) how to write a case condition in that case.
Thanks!
If the usage of a case is not compulsory, try and use some regex validation to have more control on what is allowed and what not:
[[ $input =~ ^[1-9][0-9]*$ ]]
# ^ ^ ^ ^
# beginning | | end
# | any digit
# a digit from 1 to 9
This checks that the data in $input contains a number that does not start with 0.
$ r=001
$ [[ $r =~ ^[1-9][0-9]*$ ]] && echo "yes"
$
$ r=1
$ [[ $r =~ ^[1-9][0-9]*$ ]] && echo "yes"
yes
$ r="3+1"
$ [[ $r =~ ^[1-9][0-9]*$ ]] && echo "yes"
$
You can then check if the number is lower than the stored one:
[ $r -le $num ]
All together:
$ num=15
$ r=5
$ [[ $r =~ ^[1-9][0-9]*$ ]] && [ $r -le $num ] && echo "yes"
yes
$ r=19
$ [[ $r =~ ^[1-9][0-9]*$ ]] && [ $r -le $num ] && echo "yes"
$
$ r="3+1"
$ [[ $r =~ ^[1-9][0-9]*$ ]] && [ $r -le $num ] && echo "yes"
$
read -p "enter number" yournumber
re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
echo "error: Not a number" >&2; exit 1
fi
This is only code rest of the things you need to do it.
I've bumped into a Nagios check script which has been written by someone who already left my company and there's an operator there which I can't understand it's use.
This is the relevant part from the shell script:
if [[ "$URL" =~ $ACTIVE ]] && [[ "$URL2" =~ $ACTIVE2 ]]; then
echo "OK: $HOST is ACTIVE in the Load Balancer"
exit 0
My question is:
What is this =~?
I've checked about it in the internet and found that it's a bitwise which "Flips the bits in the operand", but I don't understand where and how to use it, can you please elaborate?
Edit #1:
This is the full script:
#!/bin/bash
#Purpose: Checks if proxy is active in the LB
#Date: May 09, 2011
#Variables
HOST=$1
URL=`wget --timeout=60 -w 3 -qO- http://$HOST:8080/proxy/keepalive?file=/workspace/temp/1`
URL2=`wget --timeout=60 -w 3 -qO- http://$HOST:8080/proxy/keepalive?file=/workspace/temp/1.txt`
ACTIVE="1"
ACTIVE2="ppp"
LOG="/tmp/PROXY-LB.log"
#Begin Code
if [ -z $HOST ]; then
echo "You must specify IPADDRESS (e.g. 68.67.174.34)"
exit 3
fi
if [[ "$URL" =~ $ACTIVE ]] && [[ "$URL2" =~ $ACTIVE2 ]]; then
echo "OK: $HOST is ACTIVE in the Load Balancer"
exit 0
else
echo "*** Problem: $HOST is out from the Load Balancer"
echo "`date`: *** HOST $HOST is out from the Load Balancer" >> $LOG 2>&1
exit 2
fi
#END
My question is, couldn't the coder use this (without the ~) instead?
if [[ "$URL" = $ACTIVE ]] && [[ "$URL2" = $ACTIVE2 ]]; then
Edit #2:
Here are some examples I tried:
$ d="hello"
$ [[ "$d" =~ *ll* ]] && echo "yes"
$ [[ "$d" =~ he* ]] && echo "yes"
yes
$ [[ "$d" =~ *lo ]] && echo "yes"
$
Edit #3:
Okay, I've done some more tests and I believe I understand it now:
$ [[ "$d" =~ he* ]] && echo "yes"
yes
$ [[ "$d" =~ *lo ]] && echo "yes"
$ [[ "$d" =~ h* ]] && echo "yes"
yes
$ [[ "$d" =~ lo$ ]] && echo "yes"
yes
$ [[ "$d" =~ ^he ]] && echo "yes"
yes
$ [[ "$d" =~ [a-z]ll[a-z] ]] && echo "yes"
yes
$
Thank you all for your help and information!
It is used to perform comparisons in strings.
if [[ "$URL" =~ $ACTIVE ]] && [[ "$URL2" =~ $ACTIVE2 ]]; then
Checks if $URL contains the content of the variable $ACTIVE and if $URL2 contains the content of the variable $ACTIVE2.
See a test:
$ d="hello"
$ [[ "$d" =~ he* ]] && echo "yes"
yes
$ [[ "$d" =~ *ba* ]] && echo "yes"
$
$ [[ $d =~ .*ll.* ]] && echo "yes"
yes
In the last one you have to indicate the regex properly. It is equivalent to using == and just *ll*.
$ [[ $d == *ll* ]] && echo "yes"
yes
From man bash -> 3.2.4.2 Conditional Constructs:
An additional binary operator, =~, is available, with the same
precedence as == and !=. When it is used, the string to the
right of the operator is considered an extended regular expression and
matched accordingly (as in regex(3)). The return value is 0 if the
string matches the pattern, and 1 otherwise. If the regular
expression is syntactically incorrect, the conditional expression's
return value is 2.
Unfortunately i tried this and it doesn't work, i must use the [[ ]]
read input
for i in input
do
if [[ i = "$input" ]]
then
echo "i"
fi
done
when I run this nothing happens, it only reads my input
This line:
if [[ i = "$input" ]]
should be:
if [[ "$i" = "$input" ]]
OR:
if [[ "$i" == "$input" ]]
PS: Same thing for input also.
Remember that variables in shell are accessed with $ prefix.
May be you can re-factor your script to this:
read input
for i in $input
do
[[ "$i" == "something" ]] && echo "$i"
done
I think when you use only numbers you can also try:
for i in input
do
if [[ $i -eq "$input" ]]
then
echo "$i"
fi
done
I'm trying to check if some string from length 1 and has only following chars: [RGWBO].
I'm trying the following but it doesn't work, what am I missing?
if [[ !(${line[4]} =~ [RGWBO]) ]];
This is what you want:
if [[ ${line[4]} =~ ^[RGWBO]+$ ]];
This means that the string right from the start till the end must have [RGWBO] characters one or more times.
If you want to negate the expression just use ! in front of [[ ]]:
if ! [[ ${line[4]} =~ ^[RGWBO]+$ ]];
Or
if [[ ! ${line[4]} =~ ^[RGWBO]+$ ]];
This one would work with any usable version of Bash:
[[ -n ${LINE[0]} && ${LINE[0]} != *[^RGWB0]* ]]
Even though I prefer the simplicity of extended globs:
shopt -s extglob
[[ ${LINE[0]} == +([RGWBO]) ]]
Use expr (expression evaluator) to do substring matching.
#!/bin/bash
pattern='[R|G|W|B|O]'
string=line[4]
res=`expr match "$string" $pattern`
if [ "${res}" -eq "1" ]; then
echo 'match'
else
echo 'doesnt match'
fi
Approach
Test the string length with ${#myString}, if it's egal to 1 proceed to step 2 ;
Does is contains your pattern.
Code
re='[RGWBO]';
while read -r line; do
if (( ${#line} == 1 )) && [[ $line == $re ]]; then
echo "yes: $line"
else
echo "no: $line"
fi
done < test.txt
Resources
You may want to look at the following links:
Bash: Split string into character array's answer ;
Length of a string, use ${#myString} ;
Extracting parts of strings, use ${myString:0:8} ;
Data
The test.txt file contains this
RGWBO
RGWB
RGW
RG
R
G
W
B
O
V