3

I have recently switched from bash to zsh and now when I type

ls *

It does not simply list all files in this directory, but shows a tree of two levels.

Also

rm -rf somepath/*

fails with the output zsh: no matches found:

This used to work just fine with bash. Can anyone help me to get this behaviour back?

I do have oh-my-zsh installed.

  • 7
    Bash would expand the * wildcard to directories (thus ls would show those directories' contents); did you change bash's behavior somehow? – Jeff Schaller May 28 at 14:12
  • I got a bit confused about this. It turns out this was all just a matter of using sudo and globbing not working with sudo. – morja May 28 at 22:39
9

ls * would have the same effect in bash. No matter what the shell is, what happens is that the shell first expands the wildcards, and then passes the result of the expansion to the command. For example, suppose the current directory contains four entries: two subdirectories dir1 and dir2, and two regular files file1 and file2. Then the shell expands ls * to ls dir1 dir2 file1 file2. The ls command first lists the names of the arguments that are existing non-directories, then lists the contents of each directory in turn.

$ ls
dir1  dir2  file1  file2
$ ls -F
dir1/  dir2/  file1  file2
$ ls *
file1  file2

dir1:
…

dir2:
…

If ls behaved differently in bash, either you've changed the bash configuration to turn off wildcard expansions, which would turn it off everywhere, or you've changed the meaning of the ls command to suppress the listing of directories, probably with an alias. Specifically, having

alias ls='ls -d'

in your ~/.bashrc would have exactly the effect you describe. If that's what you did, you can copy this line to ~/.zshrc and you'll have the same effect.


The fact that rm -rf somepath/* has a different effect in bash and zsh when somepath is an empty directory is a completely different matter.

In bash, if somepath/* doesn't match any files, then bash leaves the wildcard pattern in the command, so rm sees the arguments -rf and somepath/*. rm tries to delete the file called * in the directory somepath, and since there's no such file, this attempt fails. Since you passed the option -f to rm, it doesn't complain about a missing file.

In zsh, by default, if a wildcard doesn't match any files, zsh treats this as an error. You can change the way zsh behaves by turning off the option nomatch:

setopt no_nomatch

I don't recommend this because having the shell tell you when a wildcard doesn't match is usually the preferable behavior on the command line. There's a much better way to tell zsh that in this case, an empty list is ok:

rm -rf somepath/*(N)

N is a glob qualifier that says to expand to an empty list if the wildcard doesn't match any file.

| improve this answer | |
  • Thank you! I see that I am mistaken regarding the use of ls *. Regarding the rm, I did find the cause. It was due to using sudo. Could it be that the globbing does not work with sudo? – morja May 28 at 22:17
  • @morja Globbing works with sudo, but it takes place before sudo. So globbing won't work in a directory that you don't have permission to read. This is the same in bash and in zsh. – Gilles 'SO- stop being evil' May 28 at 23:28
  • Yes, I understand now. Thanks a lot! – morja May 29 at 8:46
1

You have configured the Bourne Again shell with a non-default option, nullglob. This makes ls * in an empty directory turn into plain ls, and rm -rf somepath/* where that subdirectory is empty turn into rm -rf.

To achieve the same effect with the Z shell, you need a similar non-default option, by the same name:

setopt nullglob

The Z shell has another option that turns on slightly different behaviour:

setopt cshnullglob
With this option, ls * and rm -rf somepath/* are still flagged as matching errors, but rm -rf empty/* hasfiles/* is not and ignores the empty/*, not passing it to rm. It allows some patterns to expand to nothing, as long as at least one does not.

| improve this answer | |
  • 1
    Presumably ls in an empty directory wouldn’t show “a tree of two levels”... – Stephen Kitt May 28 at 17:04
  • If the directory was empty, zsh should presumably also croak for the glob in ls, like it does for the one in rm – ilkkachu May 28 at 17:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.