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 \\
.