4

I ran the following command on zsh

sudo apt-get install rhythmbox* 

It produced an error, when I ran the same command in bash it worked. Why does this happen?

How can I make the above command work on zsh?

Zanna
  • 70,465
banarun
  • 197

3 Answers3

9

Here's what happens

Bash will try to evaluate the pattern rhythmbox* on the current working directory. As it is very unlikely there will be any file or directory starting with the sequence of rhythmbox, it will not expand, but Bash will provide it as an argument to apt-get here.

Note that if you have a file there with the name rhythmbox-test then it won't work as it will be expanded and rhythmbox-test will be provided as the argument to apt-get.

Solution: escape or quote it!

So, to reliably use the patters in apt-get in a Bash shell, you should always escape it. Use quotes or the backslash, e.g.

sudo apt-get install rhythmbox\* 

or

sudo apt-get install "rhythmbox*"

About the same goes for zsh.

The expansion of the pattern is called globbing.

Demo

touch aa ab  # creates files aa and ab
ls a*        # lists both files as Bash provided ls two arguments.
ls 'a*'      # No such file or directory. Bash provided literally a* to ls.
ls a\*       # No such file or directory. Same as above.
gertvdijk
  • 67,947
3

You need to use quotes to prevent zsh from expanding the '*' (you want apt-get to expand the * )

sudo apt-get install "rhythmbox*"
Panther
  • 102,067
1

Use ^rhythmbox instead (with ^). Usually avoid * when installing or removing packages.

Even if you quote it so the shell passes it unchanged, * doesn't do what most people expect when it appears in a package name with most apt/apt-get actions, including install, remove, and purge. Avoid * in the pattern that follows these actions unless you know precisely what it does and why. Usually * is not what you actually want and this is one of those times when it seems you do not. * does not mean "any characters" in this context.

The proper way to tell apt-get to install all packages whose names start with rhythmbox is:

sudo apt-get install ^rhythmbox

This also works with apt install. Similarly, if you needed to remove such packages, you could specify ^rhythmbox after the remove or purge action.

^rhythmbox matches all package names that start with rhythmbox because ^ is the start-of-line (or, in this case, start-of-string) anchor.


The problem with * in the name of a package to install or remove is that apt and apt-get interpret it as a regular expression rather than a glob. In a regular expression, * means "zero or more of the preceding item." So when you run sudo apt-get install with rhythmbox\*, 'rhythmbox*', "rhythmbox*", or (when the shell doesn't expand *) rhythmbox*, you are actually telling apt-get to install every package with rhythmbo anywhere in its name.

  • Not rhythmbox, rhythmbo, because the x is to appear any number of times--zero or more times.
  • Not at the beginning of the name, or as the whole name, but anywhere in its name.

In the specific case of this particular package, this will likely not cause huge problems, as there are probably few packages that have rhythmbo in their names but don't start with rhythmbox. But with packages whose names are shorter, especially when using the remove or purge actions, this is often disastrous.


The main exception to this is apt list. The list action does interpret * and ? as globbing characters rather than as regular expression metacharacters. So you can search for packages whose names start with rhythmbox like this:

apt list rhythmbox\*

(Or with 'rhythmbox*' or "rhythmbox*".)

But to install such packages--and not install more packages than you mean to--you still need to use:

sudo apt install ^rhythmbox

Or you can just pass the specific package names you need. Using apt list can help you find them.

Eliah Kagan
  • 117,780