217

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.

3
  • 1
    This really is the wrong approach -- instead of using grep, use shopt -s nullglob and then just refer to *.exe *.mp3 *.mp4. See mywiki.wooledge.org/ParsingLs Commented Sep 19, 2009 at 6:15
  • 5
    I can't figure out whether or not "Slow Leopard" was a typo... Commented May 19, 2018 at 1:24
  • 1
    @Wowfunhappy hahaha, definitely was a typo, I recall thinking Snow Leopard was quite fast. Commented May 20, 2018 at 4:50

12 Answers 12

453

Why not:

ls *.{mp3,exe,mp4} 

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

Sign up to request clarification or add additional context in comments.

6 Comments

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.
@RichardVenable add the -d switch to prevent that directories are recursed.
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)
I redirected stderr to /dev/null to avoid ls: *.exe: No such file or directory eg: ls *.{zip,tar.gz,tar} 2>/dev/null
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.
|
64

egrep -- extended grep -- will help here

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

should do the job.

4 Comments

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.
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: 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).
There's a missing apostrophe at the end. Other than that it seems to work.
49

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)' 

4 Comments

On Mac OS X: find . -iregex '.*\(mp3\|mp4\|exe\)'
andi, that didn't work for me on mac os. But this did: find -E . -regex '.*(mp3|mp4|exe)'
This solution will load files like: mysupermp3.jpg consider adding the $ at the end of the regex and the \\. before the extensions
@Panthro: actually, it won't. Find appears to use implied anchors. The dot is a good idea (only one backslash is needed).
22

the easiest way is to just use ls

ls *.mp4 *.mp3 *.exe 

6 Comments

Thanks, but I already tried that and I didn't like the errors you get when there is no file. Thou I could of fixed that by doing: ls *.mp4 *.mp3 *.exe 2> /dev/null Only thought of that now thou :P
I am surprised that ls doesn't have some sort of silent option.
In bash, you can do "set -o nullglob", and you wont get the errors.
My mistake - that should be "shopt -s nullglob" not the set -o command
Or just use "echo": echo *.mp4 *.mp3 *.exe
|
14

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 

2 Comments

Same comment as I gave to Good Time Tribe.
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.
12

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

find -iname '*.mp3' -o -iname '*.exe' -o -iname '*.mp4' 

1 Comment

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.
8

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.

5 Comments

I got a syntax error using your example??? 'bash: syntax error near unexpected token `('
I guess you mean ls *.@(mp3|exe|mp4). You need shopt -s extglob for this to work. By the way, ls is useless too, you could just do printf '%s\n' *.@(mp3|exe|mp4).
I get the syntax unexpected token message on macOS 10.13
what if my folder has .h & .hpp files & I only want to list .h
is there a way to negate "ls *.(mp3|exe|mp4)", basically I wanna see all other files but not these 3 extensions? later I want to change the code to remove, i.e., removing ls and placing rm there.
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.

Comments

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

2 Comments

Thanks, but a bit inconvenient using up several lines.
This + mdfind yields the best / fastest searches EVER! mdfind -name querystring | grep "\.h$" finds all headers with quesrystring in the file title. pronto.
0

ls -R | findstr ".mp3"

ls -R => lists subdirectories recursively

1 Comment

Isn't findstr a windows specific command?
0

it is easy try to use this command :

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

Comments

-1

Here is one example that worked for me.

find <mainfolder path> -name '*myfiles.java' | xargs -n 1 basename 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.