Created
May 25, 2018 08:39
-
-
Save kokumura/a6d819ddcb4efe54c5541fc15e1d0347 to your computer and use it in GitHub Desktop.
lineinfile in Shell Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Ansible 'lineinfile' like function in Shell Script. | |
# Works on both Bash and Zsh. | |
function lineinfile(){ | |
if [[ $# != 3 ]];then | |
local THIS_FUNC_NAME="${funcstack[1]-}${FUNCNAME[0]-}" | |
echo "$THIS_FUNC_NAME - 3 arguments are expected. given $#. args=[$@]" >&2 | |
echo "usage: $THIS_FUNC_NAME PATTERN LINE FILE" >&2 | |
return 1 | |
fi | |
local PATTERN="$1" | |
local LINE="$2" | |
local FILE="$3" | |
if grep -E -q "${PATTERN}" "${FILE}" ;then | |
## solution 1: works with GNU sed well, but not works with BSD sed. | |
# sed -E -i '' "/${PATTERN//\//\\/}/c${LINE}" "${FILE}" | |
## solution 2: works with both (GNU|BSD) sed, but get useless *.bak file generated. | |
# sed -E -i.bak "/${PATTERN//\//\\/}/c\\"$'\n'"${LINE}" "${FILE}" | |
## solution 3: give up to use sed, using perl instead. | |
PATTERN="${PATTERN}" LINE="${LINE}" perl -i -nle 'if(/$ENV{"PATTERN"}/){print $ENV{"LINE"}}else{print}' "${FILE}" | |
else | |
echo "$LINE" >> "$FILE" | |
fi | |
} | |
###################### | |
# example | |
###################### | |
# write some lines to 'test.txt' | |
cat <<EOF > test.txt | |
foo = FOO1 # first occurence | |
bar = BAR | |
foo = FOO2 # second occurence | |
EOF | |
# usage: lineinfile PATTERN LINE FILE | |
# if some lines in FILE matches PATTEN, all of them are replaced with LINE. | |
lineinfile '^foo\s*=\s*' "foo = POO # changed!" test.txt | |
# if no lines in FILE matches PATTERN, LINE is appended to end of FILE. | |
lineinfile '^baz\s*=' "baz = BAZ" test.txt | |
cat test.txt | |
# now 'test.txt' will contain: | |
# | |
# foo = POO # changed! | |
# bar = BAR | |
# foo = POO # changed! | |
# baz = BAZ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If the
*.bak
is useless, why is it there in the first place?from GNU sed man:
And for BSD sed the
-i ''
should work as it doesn't seem to be optional there.I don't really see a reason to keep the solution 1 and solution 2 here in place instead of combining them into one that is free from:
It seems like:
could do the trick (I haven't tested that).
Maybe there was a reason having both solutions that I miss and it's worth mentioning it?