LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Help with function in script (https://www.linuxquestions.org/questions/linux-newbie-8/help-with-function-in-script-4175429517/)

Tiago85 09-28-2012 09:28 PM

Help with function in script
 
Hi.

I'm new in linux and I'm trying to make a function that takes two string arguments and check if the first is included on the second.

I've made the following code but I'm getting the "syntax error near unexpected token 'then'". The error is at line 13.

I can't figure what is the error.

#!/bin/bash

match() {
# arg $1
# arg $2

FOUND=-1

for (( i=0; i<${#2}; i++ ))
do
for (( a=0; a<=${#1}; a++ ))
do
if [ $a == ${#1} ]; then #ERROR LINE
FOUND=$((i+a))
break
fi

if [ ${2:$((i+a)):1} == ${1:$a:1} ];
then
echo "True"
else
echo "False"
break
fi

done

fi
done
}


Thank you.

nugat 09-29-2012 12:02 AM

I don't get the same error as you, but I do get an error. I think you have an extra "fi" in there. Look at this copy of your code, formatted for easier reading, with the extra "fi" commented out:

Code:

#!/bin/bash

match() {
# arg $1
# arg $2

  FOUND=-1

  for (( i=0; i<${#2}; i++ )); do
    for (( a=0; a<=${#1}; a++ )); do
      if [ $a == ${#1} ]; then #ERROR LINE
        FOUND=$((i+a))
        break
      fi
      if [ ${2:$((i+a)):1} == ${1:$a:1} ]; then
        echo "True"
      else
        echo "False"
        break
      fi
    done
#fi
done
}

I'm not so sure your code is doing what you want it to do, though...

grail 09-29-2012 12:50 AM

Just to be clear, please provide an example of input, both correct and incorrect, so we may understand what your script is attempting to do?

Also, is this homework of some kind? I ask as there are much shorter solutions (assuming I understand what you require, hence first question above).

Tiago85 09-29-2012 03:13 AM

Hi.

nugat, you are right.
I forgot to delete that fi. For debug I have another if condition between the two for's, but I don't need them.
Without that if then fi the script doesn't work too.

grail, unfortunately it's not SOLVED.

The main goal of this script is to compare two strings and check if the first string is included on the second string.
For exemple running ./match.sh "al" "alright" will return true.
Running ./match "all" "alright" will return false.

This is not a homework for any kind of school.
I have/want to learn script language and I found a problem on the internet and I'm try to resolve it.
I'm not asking for a solution to that problem, I'm try to understand why my script is not working. :(

I have read that this ${1:$a:1} will give me the "a" (number) caracter on the $1 variable.
And I have read that #1 will give me the lenght of $1 variable.

I don't think I will need anything more to solve this question. I just need to understand and solve the error. :(

Thank you.

Weapon S 09-29-2012 03:22 AM

Have you tried echoing all your variables in the loops? You might be surprised ;)
BTW grep is a regular expression program. It would solve this in an instant. Regular expressions are things distinct from bash scripts, so pick your poison your interest.

Tiago85 09-29-2012 04:45 AM

Thanks Weapon S.

The problem is that I can not even try my script, because when I run ./match.sh "al" "already" i get the error "syntax error near unexpected token 'then'.
I did not want to try regular expression because if I can't do a simple script, i should learn first the basic and then try hard things.

I'm making this script just to learn, and not to achieve anything.

grail 09-29-2012 04:51 AM

Firstly, my signature mentions marking the problem as SOLVED once you have an answer and not that you need to do it now.

As for the code, I am not really sure I understand the process you are using, but I thought I would point out some issues:
Code:

if [ $a == ${#1} ]; then
1. As your using bash I would promote using [[ over [ as it has more features

2. As the value of $a and ${#1} are both numbers, you should be using -eq and not ==, see man test

3. Instead of [ or [[ you would also be better suited in this instance to use (( as this is the correct bracketing system for testing numbers
Code:

if (( a == ${#1} )); then
Note: Yes the $ sign is not required for variables but still required for parameters

4. Lastly, this test would appear useless as you are in a for loop with 'a' as the counter and ${#1} as the maximum value, hence this test will ALWAYS be true at the end of the loop
and not before.

As an overall for the function, what happens if the length parameter 1 is longer than that of parameter 2? Surely this will end in error as you will step off the end of
the length of the second variable.

Also @ Weapon S, whilst I agree that grep is designed for regular expressions, the following statement is erroneous:
Quote:

Regular expressions are things distinct from bash scripts
As an example:

http://tldp.org/LDP/abs/html/regexp.html

Tiago85 09-29-2012 05:57 AM

Thank you grail.

I have made the changes and now the script doesn't return any error. :D

Code:

#!/bin/bash

match(){
# agr $1 needle
# arg $2 haystack

if [ -z "$1" ]; then
        echo "The argument pattern is empty."
        exit 1
fi

if [ -z "$2" ]; then
        echo "The argument text is empty."
        exit 1
fi

if ((${#1} -gt ${#2})); then
        echo "FALSE"
        exit 0
fi

SEARCH=-1

for(( i=0; i<${#2}; i++ ))
do
        if [[ "${2:$i:1}" == "${1:0:1}" ]]; then

                for(( a=0; a<=${#1}; a++ ))
                do
                        if (($a -eq ${#1} )); then       
                                SEARCH=$((i+a))
                                break
                        fi

                        if(( ${2:$((i+a)):1} == ${1:$a:1} )); then
                                echo "True"
                        else       
                                echo "False"
                                break
                        fi
                done
        fi
done
exit 0
}

match $1 $2

But when i run ./match2.sh as asd it return the folowing errors.

Code:

$ ./match2.sh as asd
./match2.sh: line 17: ((: 2 -gt 3: syntax error in expression (error token is "3")
./match2.sh: line 30: ((: 0 -eq 2 : syntax error in expression (error token is "2 ")
True
./match2.sh: line 30: ((: 1 -eq 2 : syntax error in expression (error token is "2 ")
True
./match2.sh: line 30: ((: 2 -eq 2 : syntax error in expression (error token is "2 ")
./match2.sh: line 35: ((: d ==  : syntax error: operand expected (error token is " ")
False

When I compare two number and the result is false I get this error. This should not enter on IF condition?

nugat 09-29-2012 08:02 AM

Quote:

Originally Posted by Tiago85 (Post 4792378)
But when i run ./match2.sh as asd it return the folowing errors.

Code:

$ ./match2.sh as asd
./match2.sh: line 17: ((: 2 -gt 3: syntax error in expression (error token is "3")
./match2.sh: line 30: ((: 0 -eq 2 : syntax error in expression (error token is "2 ")
True
./match2.sh: line 30: ((: 1 -eq 2 : syntax error in expression (error token is "2 ")
True
./match2.sh: line 30: ((: 2 -eq 2 : syntax error in expression (error token is "2 ")
./match2.sh: line 35: ((: d ==  : syntax error: operand expected (error token is " ")
False


if i replace those '(( ))' with '[ ]' i don't get that error.

this seems to be a very convoluted way to look for a string though. and why are you comparing numbers if you want to be looking for one string in another?

you can still use grep, as another has mentioned, and still make it a simple script, e.g.:

Code:

#!/bin/bash

match() {
  regex=$1
  string=$2
  echo $string|grep --color $regex && return 0 || return 1
}

[ $# -ne 2 ] && echo "Usage: $0 <REGEX> <STRING>" && exit 1
match $1 $2 && echo MATCH || echo NO MATCH


grail 09-29-2012 08:32 AM

You might need to pay a little closer attention to the information I provided.

When using [ or [[ for numbers you need to use -eq.

When using (( you use ==

Also the simpler test shown by nugat of checking the number of parameters would negate checking each parameter but does introduce the problem
of either parameter being empty. Of course searching for an empty parameter or in an empty one shouldn't cause too many issues (???).

I am guessing you are using the function just to learn these as of course it is not needed in this case.

Finally, bash does not require the added use of grep should you wish to perform your regex. As others have now shown other
solutions, I will add a slightly simpler version:

Code:

#!/bin/bash

match() {
        if [[ $2 =~ $1 ]]
        then
                echo FOUND
        else
                echo NOT FOUND
        fi
}

(( $# == 2 && ${#1} )) || { echo "Usage: $0 <REGEX> <STRING>" && exit 1; }

match "$1" "$2"

This also disallows the regex to be empty. If you are not sure why this is needed, try removing '&& ${#1}' and test for your self.

Thad E Ginataom 09-29-2012 08:49 AM

Nugat, I am a decade out of practice, and trying to pick up again on this stuff. There has already been a suggestion that you echo variables in a loop. I'd second that, and also suggest that you put this near the top of your scripts for testing:
Code:

set -xv
This will give you lots of information about what the shell is actually doing with your script, and, especially, you will be able to see how variables are being used/substituted/tested. This will help to sort out a host of errors with quotes, command substitutions, tests, etc etc.

I used to use /bin/sh, with some use of ksh. If this advice needs tailoring for bash, then I shall be happy to learn about that from others, please.

Tiago85 09-29-2012 12:33 PM

It's solved
Thank you all for all information that you write.

Now i can move forward. ;)

grail 09-29-2012 12:46 PM

Please use the Thread Tools to mark the question as SOLVED.


All times are GMT -5. The time now is 09:30 PM.