Adding line with text between pattern and next occurence of the same pattern in bash
I am writing a bash script that modifies a file that looks like this:
--- usr1 ---
data data data data
data data data data
data data data data
--- usr2 ---
data data data data
data data data data
--开发者_运维知识库- usr3 ---
data data data data
--- endline ---
One question is: How to add next user line --- usrn ---
after last user data lines?
Second one is: How to delete specific user data lines (data lines and --- userx ---
) i.e. I would like to delete usr2 with all his data set.
It must work on bash 2.05 :) and I think it will use awk or sed, but I'm not sure.
A little edit here: In fact usernames are not numbered. We don't know what users will come up with. We only know that the name will be inside---
patternGiven a username in a variable:
username="kasper"
Delete a user section:
sed "/$username/{:a;N;/\n--- [^[:blank:]]* ---\$/{s/.*\n//;b};ba}" inputfile
or for some versions of sed
(edited):
sed -e "/$username/{" -e ':a' -e 'N' -e '/\n--- [^[:blank:]]* ---$/{s/.*\n//' -e 'b' -e '}' -e 'ba' -e '}' inputfile
Edit: a possible variation to accommodate leading and trailing whitespace:
sed -e "/$username/{" -e ':a' -e 'N' -e '/\n[[:blank:]]*---[[:blank:]]*[^[:blank:]]*[[:blank:]]*---[[:blank:]]*$/{s/.*\n//' -e 'b' -e '}' -e 'ba' -e '}' inputfile
Add the next user section:
sed "s/--- end/--- $username ---\ndata data data data\ndata data data data\n&/"
or
sed "/--- end/i--- $username ---\ndatadata data data\ndata data data data\n"
If your version of sed
supports in-place changes, you can do:
sed -i ...
Otherwise, you'll have to use a temporary file:
sed ... inputfile > tmpfile && mv tmpfile inputfile
It's best to use a utility like mktemp
or tempfile
to create a temporary file and use the name provided.
An awk solution for the 2nd part:
awk -v del="usr2" 'match($0,/^--- (.*) ---$/,a) {p = (a[1] != del)} p'
This turns the p
flag off if the head matched the user to delete, otherwise it prints every line.
Plain shell can handle this
Updated answer to include the second requirement...
#!/bin/sh
NEWUSER='John Doe'
NEWUSERDATA='how now brown cow'
REMOVEUSER='usr2'
state=COPY
while read x; do
case "$state/$x" in
*"/--- endline ---")
echo --- $NEWUSER ---
echo "$NEWUSERDATA"
state=COPY
;;
COPY/*)
if [ "$x" == "--- $REMOVEUSER ---" ]; then
state=REMOVE
fi
;;
REMOVE/---*)
state=COPY
;;
esac
if [ $state != REMOVE ]; then
echo "$x"
fi
done
Usage is something like: sh newuser.sh < usertable.txt > newusertable.txt
By the way, there is an alternative style of writing shell scripts which I might call "gnu configure" format. In "alternative style" the main loop would be:
while read x; do
case "$state/$x" in
*"/--- endline ---")
echo --- $NEWUSER ---
echo "$NEWUSERDATA"
state=COPY;;
COPY/*)
[ "$x" == "--- $REMOVEUSER ---" ] && state=REMOVE;;
REMOVE/---*)
state=COPY;;
esac
[ $state != REMOVE ] && echo "$x"
done
精彩评论