Home > database >  How to insert variable and code after pattern using sed?
How to insert variable and code after pattern using sed?

Time:01-01

I'm using a shell script to insert code with a variable after a previous code pattern in script.tex, however sed is not adding anything after the expected pattern.

cat script.tex

\multicolumn{1}{c}{st_var}

Expected result (script.tex) after script.sh is run:

\multicolumn{1}{c}{A} & \multicolumn{1}{c}{B} & \multicolumn{1}{c}{C} & \multicolumn{1}{c}{D} & \multicolumn{1}{c}{E} & \multicolumn{1}{c}{F} \\

Current result (script.tex):

\multicolumn{1}{c}{A}

The first part of the conditional is working as expected. The remaining is not being found by sed.

cat script.sh:

#!/bin/bash
var=("NA" "A" "B" "C" "D" "E" "F")
clen=$(( ${#var[@]} - 1 ))
cind=1
for (( i=1; i<${#var[@]}; i   )) ; do
  if [[ "$cind" -eq 1 ]]; then
    sed -i 's/st_var/'${var[$i]//\"/}'/g' script.tex
  elif [[ "$cind" -gt 1 ]] && [[ "$cind" -lt "$clen" ]]; then
    sstr="\multicolumn{1}{c}{${var[$i-1]//\"/}}"
    estr=" & \multicolumn{1}{c}{${var[$i]//\"/}}"
    festr=" & \multicolumn{1}{c}{${var[$i]//\"/}} \\\\"
    sed -i '/^${sstr}/ s/$/${estr}/' script.tex
  else
    sed -i '/^${sstr}/ s/$/${festr}/' script.tex
  fi
  cind=$((cind   1))
done

The var array here must have all elements double quoted for other purposes outside of this question. Also, the var array is shown here for simplicity - the letters A-F could be any random string. The first element in the array here is skipped (NA).

The best attempt so far:

script.sh:

#!/bin/bash -x
var=("NA" "A" "B" "C" "D" "E" "F")
clen=$(( ${#var[@]} - 1 ))
cind=1
for (( i=1; i<${#var[@]}; i   )) ; do
  if [[ "$cind" -eq 1 ]]; then
    sed -i 's/st_var/'${var[$i]//\"/}'/g' script.tex
  elif [[ "$cind" -gt 1 ]] && [[ "$cind" -lt "$clen" ]]; then
    sstr='\multicolumn{1}{c}{'${var[$i-1]//\"/}'}'
    estr=' \& \multicolumn{1}{c}{'${var[$i]//\"/}'}'
    festr=' \& \multicolumn{1}{c}{'${var[$i 1]//\"/}'} \\'
#     sed -i '/$sstr/r $estr/' script.tex
#    sed -i '/^'"${sstr}"'/'"${estr}"'/' script.tex
    sed -i "s/$sstr/&$estr/" script.tex
  else
    sed -i "s/$sstr/&$festr/" script.tex
#    sed -i '/^'"${sstr}"'/'"${festr}"'/' script.tex
  fi
  cind=$((cind   1))
done

Result:

\multicolumn{1}{c}{A} & multicolumn{1}{c}{B} & multicolumn{1}{c}{C} & multicolumn{1}{c}{D} & multicolumn{1}{c}{F} \ & multicolumn{1}{c}{E}

The ampersands are coming through, however the backslashes before multicolumn aren't coming through, and neither are the two backslashes at the end of the line. E and F are also flipped - F should be last.

CodePudding user response:

The following code works:

#!/bin/bash -x
var=("NA" "A" "B" "C" "D" "E" "F")
clen=$(( ${#var[@]} - 1 ))
cind=1
for (( i=1; i<${#var[@]}; i   )) ; do
  if [[ "$cind" -eq 1 ]]; then
    sed -i 's/st_var/'${var[$i]//\"/}'/g' script.tex
  elif [[ "$cind" -gt 1 ]] && [[ "$cind" -lt "$clen" ]]; then
    sstr='\\multicolumn{1}{c}{'${var[$i-1]//\"/}'}'
    estr=' \& \\multicolumn{1}{c}{'${var[$i]//\"/}'}'
    festr=' \& \\multicolumn{1}{c}{'${var[$i 1]//\"/}'} \\\\'
    sed -i "s/$sstr/&$estr/" script.tex
  else
    sed -i "s/$estr/&$festr/" script.tex
  fi
  cind=$((cind   1))
done

CodePudding user response:

Consider a different approach. Instead of adding anything incrementally, which might be hard and confusing because you have to keep "state", just do one single run. One replacement and regex pattern.

var=("A" "B" "C" "D" "E" "F")

# Generate replacement for the line.
repl=$(
  # Print var on separate lines with the stub
  printf " \multicolumn{1}{c}{%s} \n" "${var[@]}" |
  # join lines with &   space character
  paste -sd '&'
)
# add trailing \\
repl ="\\\\"
# Remove leading space
repl=${repl:1}

# Properly escape
# see https://stackoverflow.com/questions/407523/escape-a-string-for-a-sed-replace-pattern
ESCAPED_REPLACE=$(printf '%s\n' "$repl" | sed -e 's/[\/&]/\\&/g')
KEYWORD="\multicolumn{1}{c}{st_var}";
ESCAPED_KEYWORD=$(printf '%s\n' "$KEYWORD" | sed -e 's/[]\/$*.^[]/\\&/g');
# Finally run sed
set -x
sed "s/^$ESCAPED_KEYWORD$/$ESCAPED_REPLACE/"

When executed, for the following input:

\multicolumn{1}{c}{st_var}

outputs:

  sed 's/^\\multicolumn{1}{c}{st_var}$/\\multicolumn{1}{c}{A} \& \\multicolumn{1}{c}{B} \& \\multicolumn{1}{c}{C} \& \\multicolumn{1}{c}{D} \& \\multicolumn{1}{c}{E} \& \\multicolumn{1}{c}{F} \\\\/'
\multicolumn{1}{c}{A} & \multicolumn{1}{c}{B} & \multicolumn{1}{c}{C} & \multicolumn{1}{c}{D} & \multicolumn{1}{c}{E} & \multicolumn{1}{c}{F} \\

CodePudding user response:

This might work for you (GNU sed):

sed -E 's/\\multicolumn\{1\}\{c\}\{st_var\}/ ABCDEF\n&/
       :a;ta;s/(\S)(\S*\n(.*)\{st_var\})/\3{\1} \& \2/;ta
       s/ (.*)\&.*/\1\\\\/' file

Prepend a space, the values to substituted for st_var and a newline to the original sting \multicolumn{1}{c}{st_var}.

Iterate through each value prepending the original string with the new value substituted until no more values to be substituted exist.

Clean up the new string, removing the introduced newline and the original string and append \\.

  • Related