1

I am new to Bash scripting, I've used Visual Basic in Windows before and am looking for a bash equivalent string function for VB's inStr().

example in VB :

strMain = "abcABC123ABCabc"
searchStartPos = 6   'Start searching at 6th char.
subStr = "AB"        'Look for "AB".

pos = inStr(searchStartPos, strMain, subStr)

print pos

10                   'A match is found at 10th char.

I would really appreciate if someone could tell me how to do this in Bash.

plogwyn
  • 11

3 Answers3

2

I'm not aware of any existing equivalent. Some external tools may provide something out of the box, but not Bash. Bash is able to do this, but you need to tell it how to do this; i.e. you need to write some shell code.

The following shell function is an example of such code:

inStr () {
    local start string substring len pos
    start="$1"
    string="$2"
    substring="$3"

    len="${#string}"

    # strip start-1 characters
    string="${string:start-1}"

    # strip the first substring and everything beyond
    string="${string%%"$substring"*}"

    # the position is calculated
    pos=$((start+${#string}))

    # if it's more than the original length, it means "not found"
    if [ "$pos" -gt "$len" ]; then
       # not found, adjust the behavior to your needs
       # e.g. you can print -1
       return 1
    else
       printf "%s\n" "$pos"
       return 0
    fi
}

Usage:

inStr 6 "abcABC123ABCabc" "AB"

Notes:

  • In the line

    string="${string%%"$substring"*}"
    

    $substring is double-quoted. Whatever you pass as substring will always be treated literally. E.g. A*a will only match literal A*a. If the line was like this:

    string="${string%%$substring*}"
    

    then you could pass a pattern to match. In this case A*a could match the ABCa fragment. Note you need to quote such substring while invoking the function, otherwise A*a may get expanded to (possibly multiple) names of matching files (this term includes directories) in the current directory (globbing).

  • The function does not validate its input; in particular it produces garbage when a nonpositive starting position is used. Implement some tests if needed.
  • The behavior for edge cases (empty string and/or substring) may not be as you expect. Implement some logic if needed.
1

In pure bash(1), how about ...

# Returns start position or empty string if not found - removes the
# substring + everything thereafter, thus the value of the length of the
# remaining string is the actual index of the start of the substring
instr() {
  pos = ${1/$2*}
  case ${#pos} in ${#1}) echo ;; *) echo ${#pos} ;
}

strMain="abcABC123ABCabc" subStr="AB" # Look for "AB".

instr "$strMain" "$subStr" # 3

0

There's a similar function strpos(haystack, needle, pos) in PHP which has been ported to bash and other shells as well. Search for "bash strpos" and you will easily find it, for example here.

The VB function is then quite easily implemented:

inStr() { strpos $2 $3 $1; }

The pos parameter is optional in strpos.

duise
  • 1