0

I have this variable:

>echo $br_name
srxa wan-a1 br-wan3-xa1 0A:AA:DD:C1:F1:A3 ge-0.0.3 srxa wan-a2 br-wan3-xa2 0A:AA:DD:C1:F2:A3 ge-0.0.3

I am trying to create a conditional where it detects whether ge-0.0.3 is repeated more than 1 time in my variable $br_name

For example:

if [[ $br_name has ge-0.0.3 repeated more than one time ]]
then
    echo "ge-0.0.3 is shown more than once"
else
    :
fi
phuclv
  • 37,963
  • 15
  • 156
  • 475
nickcrv06
  • 127
  • 11
  • Have you heard about regex? – JRichardsz May 01 '22 at 00:19
  • Call me stupid, but I'm not actually able to just write down a regex with cardinality check that works in bash. Does `=~` even support extended regex', JRichardsz? – Christian Fritz May 01 '22 at 00:23
  • @ChristianFritz I mean it is possible to use regex to detect the complex word like this https://stackoverflow.com/a/72053019/3957754 and then use a count of matches – JRichardsz May 01 '22 at 00:40
  • You should include examples with strings like `age-0.0.31` and `ge-01013` so we can see if you want those to match `ge-0.0.3` or not, i.e. tests for partial and regexp vs string comparisons. You're getting answers that are making assumptions that I suspect you don't actually want to hold true because so far you've only provided 1 trivial sunny-day case as an example. – Ed Morton May 01 '22 at 14:01

4 Answers4

3

Bash's =~ is using extended RE.

[Bash-5.2] % check() { local s='(ge-0\.0\.3.*){2,}'; [[ "$1" =~ $s ]] && echo yes || echo no; }
[Bash-5.2] % check 'xxx'
no
[Bash-5.2] % check 'ge-0.0.3'
no
[Bash-5.2] % check 'ge-0.0.3 ge-0.0.3 '
yes
[Bash-5.2] % check 'ge-0.0.3 ge-0.0.3 ge-0.0.3 '
yes
pynexj
  • 19,215
  • 5
  • 38
  • 56
  • `$ check 'guage-0.0.395 sewage-0.0.31'` would output `yes` - I THINK that's probably undesirable but idk for sure if that'd be the expected output or not since the OP hasn't covered that or other non-trivial cases in their sample input/output. – Ed Morton May 01 '22 at 14:11
2

You can use grep -o to print only the matched phrase. Also use -F to make sure that it matches literal characters instead of a regex where . and - are special

if [[ $(echo "$br_name" | grep -Fo ge-0.0.3 | wc -l) -gt 1 ]]; then
    echo "ge-0.0.3 is shown more than once"
else
    echo "only once"
fi

For more complex patterns of course you can drop -F and write a proper regex for grep

phuclv
  • 37,963
  • 15
  • 156
  • 475
1

simple word

If your word would be "easy", you can detect the occurrences count with:

echo "123 123 123" | sed "s/123 /123\n/g" | wc -l

In which the word is replace for the same but with \n and then wc count the lines

or you can try one of these:

complex

Since your word is "complex" or you will want a pattern, you will need regex:

script.sh

count=0

for word in $1; do
  if [[ "$word" =~ .*ge-0\.0\.3.* ]]
  then
    count=$(($count+1))
  fi
done

if [ "$count" -gt "1" ];
then
  echo "ge-0.0.3 is shown more than once"
else
  if [ "$count" -eq "0" ];
  then
    echo "ge-0.0.3 is not shown"
  else
    echo "ge-0.0.3 is shown once"
  fi
fi

execution

bash script.sh "srxa wan-a1 br-wan3-xa1 0A:AA:DD:C1:F1:A3 ge-0.0.3 srxa wan-a2 br-wan3-xa2 0A:AA:DD:C1:F2:A3 ge-0.0.3"

demo

grep

With grep you can get the ocurrence count

ocurrences=( $(grep -oE '(ge-0\.0\.3)' <<<$1) )
ocurrences_count=${#ocurrences[*]}
echo $ocurrences_count

enter image description here

JRichardsz
  • 14,356
  • 6
  • 59
  • 94
  • There's several issues with this answer, including it'd match on substrings instead of whole "words" and `for word in $1` would fail if `$1` contained any globbing chars that matched with files in the current directory. – Ed Morton May 01 '22 at 14:07
  • I'm not working with files or directories. Do you have an input to test the effectiveness? – JRichardsz May 01 '22 at 16:12
  • If you're on Unix then you're working with files and directories. Try creating a file named `file` in your current directory and then use `'f*'` as the argument to `script.sh` and that'll be expanded so that `word` is set to `file` instead of `f*` by `for word in $1`. Try using an input string like `'guage-0.0.395 sewage-0.0.31'` and any of the answers will report finding 1 or more `age-0.0.3`s which is almost certainly undesirable. You're using a mix of `[...]` plus `[[...]]` plus `((...))` - just us `((...))` for math and `[[...]]` for the re test, e.g. `if (( count > 1 ))` – Ed Morton May 01 '22 at 18:00
0

Assuming you want to do a literal string match on whole words, not substrings, then this might be what you want:

$ if (( $(grep -oFw 'ge-0.0.3' <<<"$br_name" | wc -l) > 1 )); then echo 'yes'; else echo 'no'; fi
yes
Ed Morton
  • 188,023
  • 17
  • 78
  • 185