Search code examples
zshwildcardls

zsh ls: look for multiple extensions, no error if some don't exist


In a zsh terminal I want to ls all video files, that is all files ending with .mp4 or .mkv or .avi or .mov (for example).

When I do ls *.mp4 *.mkv *.avi *.mov it does what I want, except if there are no files with one or more of the given extensions.

E.g. if there are no .avi files, the above command won't list any of the other files but only say:

ls: *.avi: No such file or directory

I noticed in bash instead of zsh, it also gives this error but then still shows the files that do exist.

I assume this has to do with a difference in how wildcard matching / globbing works in zsh and bash environments.

Is there a way to just ls all files with a bunch of given extensions (or other wildcard patterns) regardless if they all occur or not?


Solution

  • You'll need more than one line of code to get this right.

    You could simply get rid of the error message by using the null glob flag, i.e.

    ls *.mp4(N) *.mkv(N)
    

    However, the problem with this is that if a pattern then produces no matching files, this results in it expanding to exactly 0 paths.

    This is fine if, say, there are no mp4 files, but at least one mkv file. Your command line would then be simply interpreted as

    ls file.mkv
    

    However, if there are neither mp4 nor mkv files, the command line would be interpreted as

    ls
    

    which will show you a list of all files in your working directory.

    Perhaps this is good enough for interactive work. If you do this from within a script, a better approach would be to first load all matching files into an array and then test whether the array is empty:

    files=( *.mp4(N) *.mkv(N) )
    if (( $#files )); then
      ls $files
    else
      print 'No mp4 or mkv files`
    fi