[etc] in regex means any one of these characters, so it won't match a literal [etc].
with sed:
sed -zi '/\[etc\]\ntransient *= *true/!s|\(.*\)\(.*\)|\1\2[etc]\ntransient = true\n|' file
'/\[etc\]\ntransient *= *true/!- checks whether the block
[etc]followed bytransient = trueexists in the file.
- checks whether the block
transient *= *true- Matches the string transient = true, with optional spaces around the = sign (* allows for zero or more spaces).
!- This negates the match, so the subsequent replacement will only occur if the pattern is not found.
s|\(.*\)\(.*\)|\1\2[etc]\ntransient = true\n|- The substitution part, which operates on the content that doesn’t match the pattern from above (![etc] block).
\1\2- These are references to the parts of the input that were matched by the first two (.*) patterns:
\(.*\)- captures any characters (except newline) before the matched pattern.
\(.*\)\1\2- captures any characters (except newline) afterThese are references to the parts of the input that were matched pattern.by the first two
\(.*\)patterns:
- captures any characters (except newline) afterThese are references to the parts of the input that were matched pattern.by the first two
[etc]\ntransient = true\n- Will be inserted if the pattern is not found.
With grep/printf:
if ! grep -qPzo '\[etc\]\s*\n\s*transient\s*=\s*true' file; then
printf '%s\n%s\n' "[etc]" "transient = true" >> file
fi
Or with grep/ed:
if ! grep -qPzo '\[etc\]\s*\n\s*transient\s*=\s*true' file; then
ed -s file <<'EOF'
$a
[etc]
transient = true
.
w
q
EOF
fi
grep will check for the pattern and if it is not found ed will run:
-s- tells ed to run in "silent" mode, suppressing most output.
$a- appends text after the last line in the file.
.- ed command to indicate the end of the text input.
w- write the changes to the file.
q- quit