hildebro
hildebro

Reputation: 569

Modifying a pattern-matched line as well as next line in a file

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

Answers (7)

potong
potong

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

Ed Morton
Ed Morton

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

petrus4
petrus4

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

Jetchisel
Jetchisel

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

Cyrus
Cyrus

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

RavinderSingh13
RavinderSingh13

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

Toto
Toto

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

Related Questions