56

Last night I was trying to burn CDs. Being annoyed with k3b and choosing to use brasero instead, I went to remove k3b.

I typed in:

sudo apt-get remove k3b

I hit tab twice and saw that I had both k3b and k3b-data on my system. Assuming that I wouldn't need k3b-data on my system without k3b, I wanted to remove it as well so I typed in:

sudo apt-get remove k3b*

Unfortunately I hit Y to confirm without looking. It uninstalled a whole lot more than k3b and k3b-data. It uninstalled packages which did not fit my k3b* regex. For example: transmission and network-manager.

I'm fairly certain that I didn't have a space between k3b and * but I don't know why else it would remove all that it did. Is there something about apt-get that I'm misunderstanding?

Eliah Kagan
  • 117,780

6 Answers6

70

The command you want is sudo apt-get remove '^k3b.*', because:

  • You need .* to match any character, any number of times
  • You need ^ to match the start of the string
  • You need to quote the regex to prevent bash from interpreting * as a wildcard

(This answer completes and summarizes previous info provided by qbi and Flimm)

Boris Dalstein
  • 860
  • 6
  • 10
  • 7
    This is safe and it's okay to use it but you don't need the .*. You can just use sudo apt-get remove ^k3b. The presence of ^ is sufficient to cause the argument to be interpreted as a regular expression, and when apt or apt-get interprets an argument as a regular expression, it matches it anywhere in the package name. That's why you need ^--to anchor the match to the start of the package name. The regular expression doesn't need to match the entire package name, just any part of it. – Eliah Kagan Aug 25 '17 at 10:48
  • 1
    @EliahKagan Thx for the additional info! (and indeed, it makes sense that if you need ^, then you don't need .*) – Boris Dalstein Aug 25 '17 at 20:43
  • 2
    note that this works for apt-get not apt. – Vincent Gerris May 20 '20 at 09:17
  • 1
    @VincentGerris it works in my apt, in Ubuntu 20.04 – qwr Dec 19 '23 at 04:53
39

The regular expression * stands for zero or arbitrarily many. So you told apt-get to remove anything which contains k3 followed by any number of b, so basically everything which contains k3. If I try your command on my system it wants to remove 58 packages.

sudo apt-get remove -s k3b*
Package k3b is not installed, so not removed
Package k3b-data is not installed, so not removed
Package k3b-dbg is not installed, so not removed
Package libcanberra-gtk3-0 is not installed, so not removed
Package libcanberra-gtk3-0-dbg is not installed, so not removed
Package libcanberra-gtk3-dev is not installed, so not removed
…
The following packages will be REMOVED:
  appmenu-gtk ardour audacity brasero brasero-cdrkit firefox-globalmenu
  gconf-editor gir1.2-appindicator-0.1 gnome-applets gnome-control-center
…
0 upgraded, 2 newly installed, 58 to remove and 0 not upgraded.
Eliah Kagan
  • 117,780
qbi
  • 19,125
  • ugh! I've been stuck working on these darn windows machines (where * just means "and anything after") for way too long! – Steve Goykovich Nov 02 '12 at 14:26
  • 14
    The * does work as a wildcard for bash like in DOS, but some commands like apt-get expect a regex. When you type sudo apt-get remove -s k3b*, bash will first look for any files in your current directory that begin with k3b. If it finds any, it will replace that argument with those filenames. If not, it will pass k3b* directly to apt-get, which will interpret it as a regex. If you don't want bash to interpret the asterisk as a wildcard first (which you probably don't), surround the argument with single quotes, like this: sudo apt-get remove -s 'k3b*' – Flimm Nov 12 '12 at 14:49
  • 3
    So the intended command would have been sudo apt-get remove -s 'k3b.*'. Just stumbled upon this answer and find it really important to know. IMHO this is quite unexpected and I would quite mark it as a "unexpected behavior" bug of apt-get... you normally expect a "glob" meaning and not a "regexp" meaning if not specified. Thanks anyway and +1! – Rmano Mar 10 '14 at 17:06
  • 1
    And for those like me who didn't know: the -s option means "simulation". It tells apt-get not to perform the operation, but simply to inform you of what would happen without the -s option. – Boris Dalstein Aug 19 '14 at 18:26
  • I think that your use of single quotes to create globbing does NOT work, at least in puppet. And that is unexpected. In 'find' program, if I write find / -iname 'project*' I will find everything that begins with project, not something that has 'project' in it and anything after it. As proof regarding puppet, notice how my results say 'regex', and the results prove it? – Dennis Jun 26 '15 at 05:45
  • (shortened)Note, selecting 'puppet' for regex 'puppet' Note, selecting 'mcollective-plugins-puppetd' for regex 'puppet' Note, selecting 'puppetmaster-common' for regex 'puppet' Note, selecting 'mcollective-plugins-puppetral' for regex 'puppet' Note, selecting 'puppet-testsuite' for regex 'puppet' ...Note, selecting 'vim-puppet' for regex 'puppet' Note, selecting 'puppetmaster' for regex 'puppet' Note, selecting 'puppet-lint' for regex 'puppet' Note, selecting 'etherpuppet' for regex 'puppet*' Package etherpuppet is not installed, so not removed – Dennis Jun 26 '15 at 05:46
  • @Flimm sudo apt-get remove -s k3b* and sudo apt-get remove -s 'k3b*' are both extremely dangerous and should not be used. If they work it is only because there don't happen to be packages installed that accidentally match the pattern. If the shell doesn't expand k3b*, apt-get matches it as a regex against any part any package name. Since k3b* is a regex that means "k, then 3, then zero or more occurrences of b," the result is that apt-get attempt to remove every package with k3 anywhere in its name (not just at the start or with b) and packages that depend on them! – Eliah Kagan Aug 23 '17 at 18:56
  • So just to be clear here, apt list package* is interpreted as a wildcard, while sudo apt-get remove package* is a regex which can match any part of a package string? Why would a package manager be designed with a deathtrap like this? – ShnitzelKiller Aug 13 '19 at 23:00
13

Use sudo apt-get remove ^k3b instead. When you install or remove packages, * is often dangerous and rarely needed. If you do use *, you should quote it, but that does not make it safer, because its tendency to select far more packages than you intend is the result of the way apt and apt-get interpret it and not an effect of pathname expansion.

  • Even safe uses of * are often unnecessary.
  • Unsafe uses are brutal. Removing k3b* removes every package that contains k3 anywhere in its name (and every package that depends on such a package). That's not a typo--containing k3 is sufficient, even without the b, because b* means "zero or more bs."

When you run apt or apt-get with the install, remove, or purge action, each subsequent argument is first1 interpreted as the name of an individual package. If a package with that exact name exists, the action is performed for it.

If there is no such package, apt and apt-get will check if the argument contains any of the common regular expression metacharacters2 ., ?, +, *, |, \[, ^, or $. If not, it's done--no package was found.

If it does contain any of those characters, then it is treated as a regular expression and matched against any part of any package name. It doesn't have to match the whole name. As others have said, * in a regular expression doesn't mean the same thing as * in a glob. ? doesn't either. In a regular expression:

  • * allows the previous item to appear any number of times--including just once or not at all--instead of exactly once.
  • ? makes the previous item optional--that is, it allows it to appear zero or one times.

apt-get(8) (man apt-get) says:

If no package matches the given expression and the expression contains one of '.', '?' or '*' then it is assumed to be a POSIX regular expression, and it is applied to all package names in the database. Any matches are then installed (or removed). Note that matching is done by substring so 'lo.*' matches 'how-lo' and 'lowest'. If this is undesired, anchor the regular expression with a '^' or '$' character, or create a more specific regular expression.

The manpage only mentions ., ?, and *, but it is incomplete, as +, |, [, ^, and $ are also sufficient to let apt-get or apt interpret the pattern as a regular expression.3

Although you can match any number of any characters with .*--not just *--you only need this if it would appear in the middle of your regular expression. Because the pattern is matched against any substring of a package name, it's pointless at the end (or beginning) of the pattern.

The manpage mentions ^ and $. These (especially ^) are key to writing safe, efficient patterns for use with the install, remove, or purge actions in apt or apt-get.

  • ^ anchors a regular expression to the beginning of the whole string. ^k3b selects all packages whose names start with k3b.
  • $ anchors a regular expression to the end of the whole string. k3b$ would select all packages whose names end with k3b.

Therefore you can use this command to safely remove the packages:

sudo apt-get remove ^k3b

Finally, in the specific case you mentioned, you might as well just pass both names yourself:

sudo apt-get remove k3b k3b-data

Then you avoid all this complexity! (Though anchoring with ^ is simple once you're used to it.) Or use brace expansion, which your shell expands into the above command:

sudo apt-get remove k3b{,-data}

1 There are two exceptions to this: (a) some options (e.g., -f, --purge) are recognized, and (b) some punctuation characters appearing at the end of an argument that would otherwise be taken as a package name to perform the action can be used to alter what is done (e.g., sudo apt install ubuntu-desktop^ installs the task rather than the package, and when ^ appears at the end ).

2 Other regular expression metacharacters exist. For example, \ is supported by all dialects of regular expressions and commonly used. ., ?, +, *, |, [, ^, and $ just happen to be the metacharacters the APT developers decided would trigger interpretation as a regular expression (after resolution as an exact package named has failed).

3 The easiest way to verify this is to simulate installation or removal with such a pattern, using the -s option as described above. For example, running apt -s install ^virtualbox shows that sudo apt install ^virtualbox would have the effect of attempting to install every package the package manager knows about whose name begins with virtualbox. However, this behavior can also be verified by examining the source code. Check the CacheSetHelper::PackageFromRegEx function in cacheset.cc.

Rinzwind
  • 299,756
Eliah Kagan
  • 117,780
1

Use .* instead of *, and put inside quotes ' '

sudo apt-get remove 'k3b.*'
Thach Van
  • 111
1

You can use apt search which has the advantage of searching in both package names and package descriptions But it is also a bit dangerous. for example, if you want to remove any package related to MY_PATTERN you can run:

sudo apt search MY_PATTERN | grep "^[^\ ]*/" -o | sed 's/\///' | xargs -I '{}' sudo apt remove -y '{}'

BE CAUTIOUS: Don't use small search patterns that can be found in many words like he, and,.... it might cause non-related package removal and therefore corruption. Before run check out the output of the apt search MY_PATTERN first.

apt search MY_PATTERN: Find the pattern in the package names and package descriptions on the remote repositories.

grep "^[^\ ]*/" -o: extract the package name.

sed 's/\///': remove / from the extracted names.

xargs -I '{}' sudo apt remove -y '{}': remove one by one.

aminag
  • 11
1

You more then likely remove a lib that had k3b in it that those programs depended on.

In short you may never know. I recommend not using a wildcard to remove things and to read things when prompted (sorry).

Also with out the -n regex searches use all fields and not just names

http://ccrma.stanford.edu/planetccrma/man/man8/apt-cache.8.html

also qbi is correct your regex is flawed from the get-go

coteyr
  • 18,288
  • One other thing, In cases like yours (k3b and k3b data) just apt-get uninstall k3b. Apt will then inform you if you have things installed that you no longer need, and what you need to do to remove them. – coteyr Nov 02 '12 at 14:21
  • wow! I never would have expected it to search within descriptions too! yeah, this is definitely something I'll never do again! (and I'll be sure to read things next time :P) – Steve Goykovich Nov 02 '12 at 14:28
  • The link is broken, would you mind clarifying how to use the -n? – Seanny123 Sep 17 '13 at 08:39
  • -n means only search in the names field. – coteyr Sep 17 '13 at 13:09
  • After trying, the -n option is not recognized by apt-get remove, only by apt-get cache. It seems that actually, apt-get remove only looks for package names, not descriptions. – Boris Dalstein Aug 19 '14 at 18:45