0

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.

Inian
  • 80,270
  • 14
  • 142
  • 161
hildebro
  • 549
  • 2
  • 5
  • 20

7 Answers7

2

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.

RavinderSingh13
  • 130,504
  • 14
  • 57
  • 93
2

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.

Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • worked as intended and IMO the easiest to understand out of all answers – hildebro Jun 27 '20 at 11:11
  • 1
    Perhaps as you are using GNU sed and only want to remove the first `#` if it starts the line `sed -i '/^#\[multilib\]/{N;s/^#//mg}' file`? – potong Jun 27 '20 at 20:42
2

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.

Ed Morton
  • 188,023
  • 17
  • 78
  • 185
1

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

Toto
  • 89,455
  • 62
  • 89
  • 125
1

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.

Jetchisel
  • 7,493
  • 2
  • 19
  • 18
0

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.

petrus4
  • 616
  • 4
  • 7
0

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
potong
  • 55,640
  • 6
  • 51
  • 83