[Solved] How can I find and replace all forms of pow(var,2) with square(var)?


[*]

Provisos and assumptions:

  • OP mentions needing to process multiple files; for this answer I’m going to focus on a single file; OP can start another question if issues arise with a multi-file solution
  • OP mentions wanting to replace some strings but it’s not clear (to me) if the original file is to be overwritten or a new file is to be created; for this answer I’m going to focus on generating the ‘modified’ output; OP can expand on this solution (below) based on final requirements
  • examples seem to imply 4x different search patterns (alpha, beta, betaR_red, epsilon_gamma); I’m going to assume there could be a variable number of patterns that need to be searched for
  • for simplicity sake I’m going to assume the search patterns are stored in an array
  • search patterns contain no leading/trailing white space
  • search patterns are relatively simple and do not contain any special characters (eg, line feeds)

Sample input file:

$ cat input.txt
pow(alpha,2) + pow(beta,2)
(3*pow(betaR_red,2))
2/pow(gammaBlue,3))
-pow(epsilon_gamma,2)+5

Array of search patterns:

$ var=(alpha beta betaR_red epsilon_gamma 'double helix')
$ typeset -p var
declare -a var=([0]="alpha" [1]="beta" [2]="betaR_red" [3]="epsilon_gamma" [4]="double helix")

The general idea is to use sed to do a multi-pattern search of the file based on the contents of the var[] array. This means we need a way to reference the array in a manner that will be suitable for a sed multi-pattern match (ie, values need to be separated by a pipe (|).

By assigning IFS='|' we can ‘reformat’ the array contents to work as a multi-pattern search string for sed:

$ echo "${var[*]}"
alpha beta betaR_red epsilon_gamma double helix
$ IFS='|' varX="${var[*]}" ; echo "${varX}"
alpha|beta|betaR_red|epsilon_gamma|double helix

Which brings us to the sed command:

$ IFS='|' sed -E "s/pow\((${var[*]}),2\)/square(\1)/g" input.txt

Where:

  • sed -E – run with extended regex support
  • pow\( / ,2\) – search for our pow(..,2) string, escaping the parens so they are not evaluated as delimiters of a regex group
  • IFS='|' / (${var[*]}) – expand array var using '|' as value delimiter; by wrapping in parens this becomes our first (and only) search group
  • square( / ) – replacement string for pow( / ,2) pattern
  • \1 – copy contents of our search group, eg, if we matched on pow(beta,2) then \1 == beta

If we execute the above as set -xv ; IFS='|' sed ...; set +xv we will generate the following ‘debug’ output showing how the sed command is expanded with the values of the var array:

++ IFS='|'
++ sed -E 's/pow\((alpha|beta|betaR_red|epsilon_gamma|double helix),2\)/square(\1)/g' input.txt

The actual output of the above sed command:

square(alpha) + square(beta)          # 2x changes
(3*square(betaR_red))                 # 1x change
2/pow(gammaBlue,3))                   # no changes
-square(epsilon_gamma)+5              # 1x change

[*]

solved How can I find and replace all forms of pow(var,2) with square(var)?