2

I am trying to create a script that will amnog other things enable source repositories in sources.list (Ubuntu). As you may or may not know the format of the repository file is something like this:

deb http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted
# deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted
# etc.

So I would like to enable source repository (uncomment lines with deb-src) but only for those preceded by the uncommented deb line. GNU sed should be perfect for this but I'm not able to make this work. This is what I have right now:

sed -i 's/^# deb-src/deb-src/gm' /etc/apt/sources.list

What I would like to have is something like this but it should replace only the commented line not everything:

sed -i 's/^deb .*$^# deb-src/deb-src/gm' /etc/apt/sources.list

So is there a way to make regex for sed that will only replace a part of matched string?

Darko Miletic
  • 1,168
  • 1
  • 13
  • 21

3 Answers3

3

Use -z in addition to -r:

sed -rz -i 's/^(deb .*\s+)^# deb-src/\1deb-src/gm' /etc/apt/sources.list

Capturing groups are necessary in order to refer to them in replacement.

revo
  • 47,783
  • 14
  • 74
  • 117
2

I personally prefer awk/perl for matching two consecutive lines

awk '/^# *deb-src/ && p ~ /^deb /{sub(/^# */, "")} {p=$0} 1'
  • p=$0 saves previous line
  • /^# *deb-src/ && p ~ /^deb / if current line starts with comment and has deb-src and previous line starts with deb
  • sub(/^# */, "") remove comment
  • 1 idiomatic way to print current record, including any changes made
  • See also: awk save modifications in place


With sed, you might need something like

sed '/^deb /{n; /^# *deb-src/ s/# *//p; D}'

or

sed '$!N; /^deb .*\n# *deb-src/ s/\n# */\n/p; D'

but I'm not very sure if this would handle all cases. See https://www.gnu.org/software/sed/manual/sed.html#advanced-sed for details. The m modifier comes into play only if you have multiple lines in pattern space. By default, sed uses newline as line separator and only has single line in pattern space. The manual link has more details

Sundeep
  • 23,246
  • 2
  • 28
  • 103
0

If your sources.list is only composed of lines like:

deb http://................
deb-src http://............

# deb http://...........
# deb-src http://.........

deb http://................
# deb-src http://............

And you don't care of removing the commented lines, you can create dinamically a new sources.list file by modifying only the lines after the ones starting by deb that are not commented:

grep -A1 "^deb " sources.list | sed "s/# deb-src/deb-src/g"

With this you grep only the lines starting by ^deb and the following one, and then you uncomment the next line (the one starting by # deb-src)

You can then send the output to a new file which can be renamed by sources.list afterwards:

grep -A1 "^deb " sources.list | sed "s/# deb-src/deb-src/g" > sources_new && mv -f sources_new sources.list

But this will only work if you have this exact syntax in your sources.list file.

Zumo de Vidrio
  • 2,021
  • 2
  • 15
  • 33