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?

1

6 Answers 6

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)

4
  • 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. Aug 25, 2017 at 10:48
  • 1
    @EliahKagan Thx for the additional info! (and indeed, it makes sense that if you need ^, then you don't need .*) Aug 25, 2017 at 20:43
  • 2
    note that this works for apt-get not apt. May 20, 2020 at 9:17
  • 1
    @VincentGerris it works in my apt, in Ubuntu 20.04
    – qwr
    Dec 19, 2023 at 4: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.
8
  • ugh! I've been stuck working on these darn windows machines (where * just means "and anything after") for way too long! Nov 2, 2012 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, 2012 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, 2014 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. Aug 19, 2014 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, 2015 at 5:45
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.

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

5
  • 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 2, 2012 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) Nov 2, 2012 at 14:28
  • The link is broken, would you mind clarifying how to use the -n?
    – Seanny123
    Sep 17, 2013 at 8:39
  • -n means only search in the names field.
    – coteyr
    Sep 17, 2013 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. Aug 19, 2014 at 18:45
1

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

sudo apt-get remove 'k3b.*'
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.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .