Search code examples
basharithmetic-expressionsparameter-expansion

Combine expressions and parameter expansion in bash


Is it possible to combine parameter expansion with arithmetic expressions in bash? For example, could I do a one-liner to evaluate lineNum or numChar here?

echo "Some lines here
Here is another
Oh look! Yet another" > $1

lineNum=$( grep -n -m1 'Oh look!' $1 | cut -d : -f 1 )  #Get line number of "Oh look!"
(( lineNum-- ))                                         # Correct for array indexing

readarray -t lines < $1

substr=${lines[lineNum]%%Y*}                            # Get the substring "Oh look! "
numChar=${#substr}                                      # Get the number of characters in the substring
(( numChar -= 2 ))                                      # Get the position of "!" based on the position of "Y"

echo $lineNum
echo $numChar

> 2
  8

In other words, can I get the position of one character in a string based on the position of another in a one-line expression?


Solution

  • As far as for getting position of ! in a line that matches Oh look! regex, just:

    awk -F'!' '/Oh look!/{ print length($1) + 1; quit }' "$file"
    

    You can also do calculation to your liking, so with your original code I think that would be:

    awk -F':' '/^[[:space:]][A-Z]/{ print length($1) - 2; quit }' "$file"
    

    Is it possible to combine parameter expansion with arithmetic expressions in bash?

    For computing ${#substr} you have to have the substring. So you could:

    substr=${lines[lineNum-1]%%.*}; numChar=$((${#substr} - 2))
    

    You could also edit your grep and have the filtering from Y done by bash, but awk is going to be magnitudes faster:

    IFS=Y read -r line _ < <(grep -m1 'Oh look!' "$file")
    numChar=$((${#line} - 2))
    

    Still you could merge the 3 lines into just:

    numChar=$(( $(<<<${lines[lineNum - 1]%%Y*} wc -c) - 1))