200

I just want to get the files from the current dir and only output .mp4 .mp3 .exe files nothing else. So I thought I could just do this:

ls | grep \.mp4$ | grep \.mp3$ | grep \.exe$

But no, as the first grep will output just mp4's therefor the other 2 grep's won't be used.

Any ideas? PS, Running this script on Slow Leopard.

Zombo
  • 1
  • 62
  • 391
  • 407
Mint
  • 14,388
  • 30
  • 76
  • 108
  • 1
    This really is the wrong approach -- instead of using grep, use `shopt -s nullglob` and then just refer to `*.exe *.mp3 *.mp4`. See http://mywiki.wooledge.org/ParsingLs – Charles Duffy Sep 19 '09 at 06:15
  • 3
    I can't figure out whether or not "Slow Leopard" was a typo... – Wowfunhappy May 19 '18 at 01:24
  • 1
    @Wowfunhappy hahaha, definitely was a typo, I recall thinking Snow Leopard was quite fast. – Mint May 20 '18 at 04:50

12 Answers12

423

Why not:

ls *.{mp3,exe,mp4}

I'm not sure where I learned it - but I've been using this.

meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
  • 1
    This isn't working for me because the extension I am using is for a directory, so the ls is listing the contents of the directory. – Richard Venable Aug 27 '13 at 02:23
  • 1
    @RichardVenable add the -d switch to prevent that directories are recursed. – Carlos Eugenio Thompson Pinzón Oct 05 '13 at 16:50
  • 14
    I like this solution but it seems to fail if you are missing any one of the filetypes. For example, you have mp3 but no .exe (Mac OSX, zsh) – JHo Dec 21 '13 at 13:42
  • 4
    I redirected stderr to /dev/null to avoid `ls: *.exe: No such file or directory` eg: `ls *.{zip,tar.gz,tar} 2>/dev/null` – Isaac Sep 06 '17 at 00:42
  • 3
    When I run ls foo*.{tar.gz,zip} directly in a shell it works, but when put this inside a shell script latest=$(ls -I '*.done' -tr ${pkgprefix}*.{tar.gz,zip} | tail -1) I got an error message: ls: cannot access 'bamtools*.{tar.gz,zip}': No such file or directory, any smarter guy can refined the answer. – Kemin Zhou Feb 09 '18 at 19:54
57

egrep -- extended grep -- will help here

ls | egrep '\.mp4$|\.mp3$|\.exe$'

should do the job.

mob
  • 117,087
  • 18
  • 149
  • 283
  • Thats it! Thanks Just realized I should have it case insensitive, so I'm using: ls | egrep -i '\.mp4$|\.mp3$|\.exe$ Incase anyone else needs help with that one day. Im always surprised by the speed I get my answer on here. – Mint Sep 19 '09 at 03:36
  • I can't see how this would work. ls without any options produces output in columns. Anchoring to the end of the line will not match properly. – camh Sep 19 '09 at 06:44
  • 4
    @camh: `ls` to a terminal (or with `-C` option) produces multi-column output. `ls` to a pipe (or with `-1`) has single column output. (Compare output of `ls` with `ls | cat`). – mob Sep 19 '09 at 07:07
  • There's a missing apostrophe at the end. Other than that it seems to work. – Björn Oct 27 '17 at 14:45
47

Use regular expressions with find:

find . -iregex '.*\.\(mp3\|mp4\|exe\)' -printf '%f\n'

If you're piping the filenames:

find . -iregex '.*\.\(mp3\|mp4\|exe\)' -printf '%f\0' | xargs -0 dosomething

This protects filenames that contain spaces or newlines.

OS X find only supports alternation when the -E (enhanced) option is used.

find -E . -regex '.*\.(mp3|mp4|exe)'
Dennis Williamson
  • 346,391
  • 90
  • 374
  • 439
19

the easiest way is to just use ls

ls *.mp4 *.mp3 *.exe
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
Joshua K
  • 457
  • 3
  • 12
13

No need for grep. Shell wildcards will do the trick.

ls *.mp4 *.mp3 *.exe

If you have run

shopt -s nullglob

then unmatched globs will be removed altogether and not be left on the command line unexpanded.

If you want case-insensitive globbing (so *.mp3 will match foo.MP3):

shopt -s nocaseglob
camh
  • 40,988
  • 13
  • 62
  • 70
  • Same comment as I gave to Good Time Tribe. – Mint Sep 19 '09 at 03:54
  • 2
    I am trying to use this with the `-R` option to list matching files in subdirectories but the option doesn't seem to have any effect and I still only get the current directory's results. – Chris Feb 13 '19 at 09:51
10

Just in case: why don't you use find?

find -iname '*.mp3' -o -iname '*.exe' -o -iname '*.mp4'
P Shved
  • 96,026
  • 17
  • 121
  • 165
  • 1
    I found this worked instead - `find . -name '*.mkv' -o -name '*.flv'` (adding as many -o clauses as required). I needed the `.` to indicate the directory and the flag `-name` not `-iname` - I'm on macOS 10.13. – Chris Feb 13 '19 at 09:55
6

For OSX users:

If you use ls *.{mp3,exe,mp4}, it will throw an error if one of those extensions has no results.

Using ls *.(mp3|exe|mp4) will return all files matching those extensions, even if one of the extensions had 0 results.

james2doyle
  • 1,399
  • 19
  • 21
5

In case you are still looking for an alternate solution:

ls | grep -i -e '\\.tcl$' -e '\\.exe$' -e '\\.mp4$'

Feel free to add more -e flags if needed.

Zombo
  • 1
  • 62
  • 391
  • 407
Hai Vu
  • 37,849
  • 11
  • 66
  • 93
3
ls | grep "\.mp4$
\.mp3$
\.exe$"
Jeff Mc
  • 3,723
  • 1
  • 22
  • 27
  • Thanks, but a bit inconvenient using up several lines. – Mint Sep 19 '09 at 03:38
  • This + `mdfind` yields the best / fastest searches EVER! `mdfind -name querystring | grep "\.h$"` finds all headers with quesrystring in the file title. pronto. – Alex Gray Nov 14 '12 at 18:32
0

ls -R | findstr ".mp3"

ls -R => lists subdirectories recursively

Mike Causer
  • 8,196
  • 2
  • 43
  • 63
vardamanpk
  • 17
  • 1
0

it is easy try to use this command :

ls | grep \.txt$ && ls | grep \.exe
-1

Here is one example that worked for me.

find <mainfolder path> -name '*myfiles.java' | xargs -n 1 basename
Jyoti Prakash
  • 3,921
  • 3
  • 21
  • 24