Using sed
To remove the first occurrence in the file:
$ sed -e ':a' -e '$!{N;ba;}' -e 's/admin,//1' file
account required pam_opendirectory.so
account sufficient pam_self.so
account required pam_group.so no_warn group=wheel fail_safe
account required pam_group.so no_warn deny group=admin,wheel ruser fail_safe
(The above was tested with GNU sed.)
How it works
-e ':a' -e '$!{N;ba;}'
This reads the whole file in at once to the pattern space. (If your file is too large for memory, this is not a good approach.)
-e 's/admin,//1'
This performs the substitution on the first occurrence of admin
and only the first occurrence.
Using BSD (OSX) sed
Wintermute reports that BSD sed cannot do branch instructions in one-liners and suggests this alternative for changing the file in place:
sed -i.bak -n '1h; 1!H; $ { x; s/admin,//; p; }' file
This reads the whole file in at once and then does the substitution once the last line has been read.
In more detail:
-n
By default, sed would print each line. This turns that off.
1h
This places the first line in the hold buffer.
1!H
For all subsequent lines, this appends them to the hold buffer.
$ { x; s/admin,//; p; }
For the last line ($), this exchanges the hold and pattern buffer so that the pattern buffer now has the complete file. s/admin,//
does the substitution and p
prints the result.
Using awk
$ awk '/admin/ && !f{sub(/admin,/, ""); f=1} 1' file >file.tmp && mv file.tmp file
This results in:
account required pam_opendirectory.so
account sufficient pam_self.so
account required pam_group.so no_warn group=wheel fail_safe
account required pam_group.so no_warn deny group=admin,wheel ruser fail_safe
How it works
/admin,/ && !f{sub(/admin,/, ""); f=1}
For each line, check to see if it contains the word admin,
and if the flag f
still has its default value of zero. If so, remove the first occurrence of admin,
and set the flag to one.
1
Print each line. 1
is awk's cryptic shorthand for {print $0}
.