Reputation: 569
I'm trying to write a script that, among other things, automatically enable multilib
. Meaning in my /etc/pacman.conf
file, I have to turn this
#[multilib]
#Include = /etc/pacman.d/mirrorlist
into this
[multilib]
Include = /etc/pacman.d/mirrorlist
without accidentally removing #
from lines like these
#[community-testing]
#Include = /etc/pacman.d/mirrorlist
I already accomplished this by using this code
linenum=$(rg -n '\[multilib\]' /etc/pacman.conf | cut -f1 -d:)
sed -i "$((linenum))s/#//" /etc/pacman.conf
sed -i "$((linenum+1))s/#//" /etc/pacman.conf
but I'm wondering, whether this can be solved in a single line of code without any math expressions.
Upvotes: 0
Views: 131
Reputation: 58578
This might work for you (GNU sed):
sed '/^#\[multilib\]/,+1 s/^#//' file
Focus on a range of lines (in this case, two) where the first line begins #[multilib]
and remove the first character in those lines if it is a #
.
N.B. The [
and ]
must be escaped in the regexp otherwise they will match a single character that is m
,u
,l
,t
,i
or b
. The range can be extended by changing the integer +1
to +n
if you were to want to uncomment n
lines plus the matching line.
To remove all comments in a [multilib]
section, perhaps:
sed '/^#\?\[[^]]*\]$/h;G;/^#\[multilib\]/M s/^#//;P;d' file
Upvotes: 0
Reputation: 204608
This will work using any awk in any shell on every UNIX box:
$ awk '$0 == "#[multilib]"{c=2} c&&c--{sub(/^#/,"")} 1' file
[multilib]
Include = /etc/pacman.d/mirrorlist
and if you had to uncomment 500 lines instead of 2 lines then you'd just change c=2
to c=500
(as opposed to typing N
500 times as with the currently accepted solution). Note that you also don't have to escape any characters in the string you're matching on. So in addition to being robust and portable this is a much more generally useful idiom to remember than the other solutions you have so far. See printing-with-sed-or-awk-a-line-following-a-matching-pattern/17914105#17914105 for more.
Upvotes: 2
Reputation: 614
Ed can do this.
cat >> edjoin.txt << EOF
/multilib/;+j
s/#//
s/#/\
/
wq
EOF
ed -s pacman.conf < edjoin.txt
rm -v ./edjoin.txt
This will only work on the first match. If you have more matches, repeat as necessary.
Upvotes: 0
Reputation: 7831
If there is only one [multilib]
entry, with ed
and the shell's printf
printf '/^#\[multilib\]$/;+1s/^#//\n,p\nQ\n' | ed -s /etc/pacman.conf
Change Q
to w
to edit pacman.conf
Match #[multilib]
;
include the next address
+1
the next line (plus one line below)
s/^#//
remove the leading #
,p
prints everything to stdout
Q
exit/quit ed
without error message.
-s
means do not print any message.
Upvotes: 1
Reputation: 88979
With GNU sed. Find row starting with #[multilib]
, append next line (N
) to pattern space and then remove all #
from pattern space (s/#//g
).
sed -i '/^#\[multilib\]/{N;s/#//g}' /etc/pacman.conf
If the two lines contain further #
, then these are also removed.
Upvotes: 2
Reputation: 133770
Could you please try following, written with shown samples only. Considering that multilib
and it's very next line only you want to deal with.
awk '
/multilib/ || found{
found=$0~/multilib/?1:""
sub(/^#+/,"")
print
}
' Input_file
Explanation:
First checking if a line contains multilib
or variable found is SET then following instructions inside it's block.
Inside block checking if line has multilib then set it to 1 or nullify it. So that only next line after multilib gets processed only.
Using sub function of awk to substitute starting hash one or more occurences with NULL here. Then printing current line.
Upvotes: 2
Reputation: 91518
A perl one-liner:
perl -0777 -api.back -e 's/#(\[multilib]\R)#/$1/' /etc/pacman.conf
modify in place with a backup of original in /etc/pacman.conf.back
Upvotes: 1