Cody Diehl
Cody Diehl

Reputation: 13

failing bash variable matching

I have been driving myself mad on this. I just don't see why it doesn't work when bash variables are untyped. There should be no reason why not.

pat1=`. $NVM_DIR/nvm.sh && nvm ls | sed 's/\x1b\[[^\x1b]*m//g' | sed -e 's/[[:alpha:]|\/\)\-\>\(|[:space:]]//g' | sed 's/[-|\*]//g' | sed '/^$/d'`
pat2=`. $NVM_DIR/nvm.sh && nvm ls node | head -1 | awk '{print $2}' | cut -d v -f2`

these expand to:

~$ echo $pat1
9.5.0
9.5.0
9.5
9.5.0
4.8.7
6.12.3
8.9.4

~$ echo $pat2
9.5.0

So I want to check if the string found in $pat2 is in $pat1 string. however it does not find it even though it clearly is in the pattern 3 times at least.

Checking for the pattern with a test like:

case "$pat1" in
  *$pat2*) 
    echo 'match'
    ;;
  *)
    echo 'nomatch'
    ;;
esac

this gives:

~$ ./test.sh 
nomatch

another test:

if [[ "$pat1" =~ "$pat2" ]]; then 
  echo 'match'
else 
  echo 'nomatch'
fi

again fails:

~$ ./test.sh
nomatch

Even tried some janky hacky method to no avail,

echo $pat1 | grep "$pat2" > /dev/null 
if [ $? -eq 0 ]; then
  echo "matched"
else
  echo "nomatch"
fi

gives the result:

~$ ./test.sh
grep: brackets ([ ]) not balanced
nomatch

Been pulling my hair out today working on this. This must be due to the fact that both variables are command substitutions, it leads me to believe it is comparing the actual commands themselves rather than their output stored in the variables. So even though they echo the output, i think it may be comparing the string of the commands itself.

am I wrong? can anyone explain why this fails to match and if its possible with bash to compare the output of two commands in a string/sub-string type of comparison?

Upvotes: 1

Views: 303

Answers (2)

Barmar
Barmar

Reputation: 781626

The grep version is almost right, but you need to quote $pat1, otherwise the newlines will be converted to spaces and everything will be on one line.

if echo "$pat1" | grep -F -q "$pat2"
then
    echo "matched"
else
    echo "nomatch"
fi

I've also added the -F option to grep so it will treat $pat2 as a fixed string rather than a regular expression.

DEMO

Upvotes: 1

shellter
shellter

Reputation: 37298

I put your pat1 and pat2 values in files and didn't need to use | anywhere.

#!/bin/bash

pat1=$(cat pat1|tr '\012' ' ')
pat2=$(<pat2)
#tst pat2="10.1"
echo "$pat1"

case "$pat1" in
  *$pat2*)
    echo 'match'
    ;;
  *)
    echo 'nomatch'
    ;;
esac

Produces

#dbg:pat2=9.5.0    pat1=9.5.0 9.5.0 9.5 9.5.0 4.8.7 6.12.3 8.9.4
match

If I un-comment the #tst pat2 line, the output is

#dbg:pat2=10.1    pat1=9.5.0 9.5.0 9.5 9.5.0 4.8.7 6.12.3 8.9.4
nomatch

Is there any chance your data was created for MS Windows? If so, check for Windows line endings with

 head -10 file | cat -vet

if you see ^M$ at the end of each line, then run dos2unix file .... (multiple file can be processed in one invocation, and the original file is overwritten with the same name.

IHTH nomatch

Upvotes: 1

Related Questions