2

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?

  • 1
    `substr=${lines[lineNum--]%%.*}; numChar=$(( ${#substr} - 2))`? Please create an [MCVE]. `For context` It would be way easier to give context as code: `echo 'some lines' > "$1"; lines=( bla ble bly )` and then give expected output from your code, thus it will create a [MCVE]. – KamilCuk May 29 '20 at 07:53
  • 1
    @KamilCuk Thank you for your comment. I edited my post accordingly. Please let me know if that is good enough. Also, thank you for your answer: I did not know that `numChar=$(( ${#substr} - 2)` was allowed. – user3334794 May 29 '20 at 08:26
  • If `lines` contains the content of the file, can't you just measure the substring already in the substitution? `Get the position of "!" based on the position of "Y"` - just get the position of `!`, so all those calculations are just to get the position of `!` in the line that contains `Oh look!`? Why is `Y` filtered? Is `10` correct? I see `!` at 7th character in `Oh look!`? – KamilCuk May 29 '20 at 08:29
  • @KamilCuk Do you mean something like: `substr=${#lines[lineNum]%%Y*}`? – user3334794 May 29 '20 at 08:33
  • What for is this line? Why is the position of `Y` relevant? Can't you just get the position of `!` from the string? Why not `${#lines[lineNum]%%!*}`? `Correct for array indexing and for the leading character` Och I see. – KamilCuk May 29 '20 at 08:33
  • 1
    @KamilCuk The minimal reproducible example I attempted just has an arbitrary situation for the question. I cannot take those shortcuts in the full script. Also, testing `${#lines[lineNum]%%!*}` gave me the length of the full line instead of the length of the substring. – user3334794 May 29 '20 at 08:36

1 Answers1

1

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))
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Thank you very much. What is the purpose of `<<<` here? And thank you for the much simpler awk solution as well. – user3334794 May 29 '20 at 08:44
  • 1
    It's called a "here string", the purpose is the redirect the result of `${lines[...]}` expansion to the standard input of `wc -c` command. – KamilCuk May 29 '20 at 08:45