Remove leading digits from a string with Bash using parameter expansion - bash

The initial string is RU="903B/100ms"
from which I wish to obtain B/100ms.
Currently, I have written:
#!/bin/bash
RU="903B/100ms"
RU=${RU#*[^0-9]}
echo $RU
which returns /100ms since the parameter expansion removes up to and including the first non-numeric character. I would like to keep the first non-numeric character in this case. How would I do this by amending the above text?

You can use BASH_REMATCH to extract the desired matching value:
$ RU="903B/100ms"
$ [[ $RU =~ ^([[:digit:]]+)(.*) ]] && echo ${BASH_REMATCH[2]}
B/100ms
Or just catch the desired part as:
$ [[ $RU =~ ^[[:digit:]]+(.*) ]] && echo ${BASH_REMATCH[1]}
B/100ms

Assuming shopt -s extglob:
RU="${RU##+([0-9])}"

echo "903B/100ms" | sed 's/^[0-9]*//g'
B/100ms

Related

bash read between two strings using parameter expansion expression

This is how my input string looks like:
INPUT_STRING="{/p1/p2=grabthistext}"
I want to print grabthistext from the INPUT_STRING.
I tried echo "${INPUT_STRING##*=}" which prints grabthistext}
How do I read only grabthistext using parameter expansion expression?
If you really want a single parameter expansion then you can use:
#!/bin/bash
shopt -s extglob
INPUT_STRING="{/p1/p2=grabthistext}"
echo "${INPUT_STRING//#(*=|\})}"
grabthistext
I would use a bash regex though:
#!/bin/bash
INPUT_STRING="{/p1/p2=grabthistext}"
[[ $INPUT_STRING =~ =(.*)} ]] && echo "${BASH_REMATCH[1]}"
grabthistext
temp="${INPUT_STRING##*=}"
echo "${temp%\}}"
grabthistext
You can do it in two steps: first extract the fragment after = as you already did, and store it in a new variable. Then use the same technique to remove the undesired } suffix:
INPUT_STRING="{/p1/p2=grabthistext}"
TEMP_STRING=${INPUT_STRING##*=}
OUTPUT_STRING=${TEMP_STRING%\}}
echo "$OUTPUT_STRING"
# grabthistext
Check it online.

How do I get the VersionName from this string?

I have this string:
package: name='my.package.name versionCode='221013140' versionName='00.00.05' platformBuildVersionName='12' platformBuildVersionCode='32' compileSdkVersion='32' compileSdkVersionCodename='12'
Using bash, how can I get this value?
00.00.05
Use parameter expansion:
#!/bin/bash
string="package: name='my.package.name versionCode='221013140' versionName='00.00.05' platformBuildVersionName='12' platformBuildVersionCode='32' compileSdkVersion='32' compileSdkVersionCodename='12'"
version=${string#* versionName=\'} # Remove everything up to the version name.
version=${version%%\'*} # Remove everything after the first quote.
echo "$version"
You can use bash regex matching operator (=~):
[[ $string =~ versionName=\'([^\']*)\' ]] && echo "${BASH_REMATCH[1]}"

How to extract a substring from a URL in bash

I have the following string
git#bitbucket.org:user/my-repo-name.git
I want to extract this part
my-repo-name
With bash:
s='git#bitbucket.org:user/my-repo-name.git'
[[ $s =~ ^.*/(.*)\.git$ ]]
echo ${BASH_REMATCH[1]}
Output:
my-repo-name
Another method, using bash's variable substitution:
s='git#bitbucket.org:user/my-repo-name.git'
s1=${s#*/}
echo ${s1%.git}
Output:
my-repo-name
I'm not sure if there's a way to combine the # and % operators into a single substitution.

Case insensitive comparision in If condition

I have this csv file and i need to count the number of rows which satisfies the condition that the row entry is betwen a certain year range and the artist_name matches the name argument. But the string matching should be case insensitive. How do i achieve that in the if loop..
I am a beginner, so please bear with me
#!/bin/bash
file="$1"
artist="$2"
from_year="$(($3-1))"
to_year="$(($4+1))"
count=0
while IFS="," read arr1 arr2 arr3 arr4 arr5 arr6 arr7 arr8 arr9 arr10 arr11 ; do
if [[ $arr11 -gt $from_year ]] && [[ $arr11 -lt $to_year ]] && [[ $arr7 =~ $artist ]]; then
count=$((count+1))
fi
done < "$file"
echo $count
The $arr7 =~ $artist part is where i need to make the modification
Bash has a builtin method for converting strings to lower case. Once they are both lower case, you can compare them for equality. For example:
$ arr7="Rolling Stones"
$ artist="rolling stoneS"
$ [ "${arr7,,}" = "${artist,,}" ] && echo "Matches!"
Matches!
$ [[ ${arr7,,} =~ ${artist,,} ]] && echo "Matches!"
Matches!
Details
${parameter,,} converts all characters in a string to lower case. If you wanted to convert to upper case, use ${parameter^^}. If you want to convert just some of the characters, use ${parameter,,pattern} where only those characters matching pattern are changed. Still more details on this are documented by manbash`:
${parameter^pattern}
${parameter^^pattern}
${parameter,pattern}
${parameter,,pattern}
Case modification. This expansion modifies the case of alphabetic characters in parameter. The pattern is expanded to
produce a pattern just
as in pathname expansion. The ^ operator converts lowercase letters matching pattern to uppercase; the , operator
converts matching uppercase
letters to lowercase. The ^^ and ,, expansions convert each matched character in the expanded value; the ^ and , expansions
match and convert
only the first character in the expanded value. If pattern is omitted, it is treated like a ?, which matches every
character. If parameter
is # or *, the case modification operation is applied to each positional parameter in turn, and the expansion is the
resultant list. If
parameter is an array variable subscripted with # or *, the case modification operation is applied to each member of the array
in turn, and
the expansion is the resultant list.
Compatibility
These case modification methods require bash version 4 (released on 2009-Feb-20) or better.
The bash case-transformations (${var,,} and ${var^^}) were introduced (some time ago) in bash version 4. However, if you are using Mac OS X, you most likely have bash v3.2 which doesn't implement case-transformation natively.
In that case, you can do lower-cased comparison less efficiently and with a lot more typing using tr:
if [[ $(tr "[:upper:]" "[:lower:]" <<<"$arr7") = $(tr "[:upper:]" "[:lower:]" <<<"$artist") ]]; then
# ...
fi
By the way, =~ does a regular expression comparison, not a string comparison. You almost certainly wanted =. Also, instead of [[ $x -lt $y ]] you can use an arithmetic compound command: (( x < y )). (In arithmetic expansions, it is not necessary to use $ to indicate variables.)
Use shopt -s nocasematch
demo
#!/bin/bash
words=(Cat dog mouse cattle scatter)
#Print words from list that match pat
print_matches()
{
pat=$1
echo "Pattern to match is '$pat'"
for w in "${words[#]}"
do
[[ $w =~ $pat ]] && echo "$w"
done
echo
}
echo -e "Wordlist: (${words[#]})\n"
echo "Normal matching"
print_matches 'cat'
print_matches 'Cat'
echo -e "-------------------\n"
echo "Case-insensitive matching"
shopt -s nocasematch
print_matches 'cat'
print_matches 'CAT'
echo -e "-------------------\n"
echo "Back to normal matching"
shopt -u nocasematch
print_matches 'cat'
output
Wordlist: (Cat dog mouse cattle scatter)
Normal matching
Pattern to match is 'cat'
cattle
scatter
Pattern to match is 'Cat'
Cat
-------------------
Case-insensitive matching
Pattern to match is 'cat'
Cat
cattle
scatter
Pattern to match is 'CAT'
Cat
cattle
scatter
-------------------
Back to normal matching
Pattern to match is 'cat'
cattle
scatter

case insensitive string comparison in bash

The following line removes the leading text before the variable $PRECEDING
temp2=${content#$PRECEDING}
But now i want the $PRECEDING to be case-insensitive. This works with sed's I flag. But i can't figure out the whole cmd.
No need to call out to sed or use shopt. The easiest and quickest way to do this (as long as you have Bash 4):
if [ "${var1,,}" = "${var2,,}" ]; then
echo "matched"
fi
All you're doing there is converting both strings to lowercase and comparing the results.
Here's a way to do it with sed:
temp2=$(sed -e "s/^.*$PRECEDING//I" <<< "$content")
Explanation:
^.*$PRECEDING: ^ means start of string, . means any character, .* means any character zero or more times. So together this means "match any pattern from start of string that is followed by (and including) string stored in $PRECEDING.
The I part means case-insensitive, the g part (if you use it) means "match all occurrences" instead of just the 1st.
The <<< notation is for herestrings, so you save an echo.
The only bash way I can think of is to check if there's a match (case-insensitively) and if yes, exclude the appropriate number of characters from the beginning of $content:
content=foo_bar_baz
PRECEDING=FOO
shopt -s nocasematch
[[ $content == ${PRECEDING}* ]] && temp2=${content:${#PRECEDING}}
echo $temp2
Outputs: _bar_baz
your examples have context-switching techniques.
better is (bash v4):
VAR1="HELLoWORLD"
VAR2="hellOwOrld"
if [[ "${VAR1^^}" = "${VAR2^^}" ]]; then
echo MATCH
fi
link: Converting string from uppercase to lowercase in Bash
If you don't have Bash 4, I find the easiest way is to first convert your string to lowercase using tr
VAR1=HelloWorld
VAR2=helloworld
VAR1_LOWER=$(echo "$VAR1" | tr '[:upper:]' '[:lower:]')
VAR2_LOWER=$(echo "$VAR2" | tr '[:upper:]' '[:lower:]')
if [ "$VAR1_LOWER" = "$VAR2_LOWER" ]; then
echo "Match"
else
echo "Invalid"
fi
This also makes it really easy to assign your output to variables by changing your echo to OUTPUT="Match" & OUTPUT="Invalid"

Resources