I have 2 questions about regex in bash expression.
1.non-greedy mode
local temp_input=\'\"a1b\", \"d\" , \"45\"\'
if [[ $temp_input =~ \\\".*?\\\
This is my first post, and I am very amateur at bash, so apologies if I haven't understood the question, but I wrote a function for non-greedy regex using entirely bash:
regex_non_greedy () {
local string="$1"
local regex="$2"
local replace="$3"
while [[ $string =~ $regex ]]; do
local search=${BASH_REMATCH}
string=${string/$search/$replace}
done
printf "%s" "$string"
}
Example invocation:
regex_non_greedy "all cats are grey and green" "gre+." "white"
Which returns:
all cats are white and white
Your regular expression matches the string starting with the first quotation mark (before ab
) and ending with the last quotation mark (after ef
). This is greedy, even though your intention was to use a non-greedy match (*?
). It seems that bash uses POSIX.2 regular expression (check your man 7 regex
), which does not support a non-greedy Kleene star.
If you want just "ab"
, I'd suggest a different regular expression:
if [[ $temp_input =~ \"[^\"]*\" ]]
which explicitly says that you don't want quotation marks inside your strings.
I don't understand what you mean. If you want to find all matches (and there are two occurrences of b
here), I think you cannot do it with a single ~=
match.
For your first question, an alternative is this:
[[ $temp_input =~ \"[^\"]*\" ]]
For your second question, you can do this:
temp_input=abcba
t=${temp_input//b}
echo "$(( (${#temp_input} - ${#t}) / 1 )) b"
Or for convenience place it on a function:
function count_matches {
local -i c1=${#1} c2=${#2}
if [[ c2 -gt 0 && c1 -ge c2 ]]; then
local t=${1//"$2"}
echo "$(( (c1 - ${#t}) / c2 )) $2"
else
echo "0 $2"
fi
}
count_matches abcba b
Both produces output:
2 b
Update:
If you want to see the matches you can use a function like this. You can also try other regular expressions not just literals.
function find_matches {
MATCHES=()
local STR=$1 RE="($2)(.*)"
while [[ -n $STR && $STR =~ $RE ]]; do
MATCHES+=("${BASH_REMATCH[1]}")
STR=${BASH_REMATCH[2]}
done
}
Example:
> find_matches abcba b
> echo "${MATCHES[@]}"
b b
> find_matches abcbaaccbad 'a.'
> echo "${MATCHES[@]}"
ab aa ad