List all files in a directory matching a string and copy output

1

1

I'm trying to create a series of playlists on my MP3 player, running Rockbox, by finding a file matching a string, using find /cygdrive/g/MUSIC -type f -name "Search Criteria" | /cygdrive/g/PLAYLIST/Playlist Name.m3u8. When I search using $ find /cygdrive/g/Music -type f -name "*Theme*", my results are:

/cygdrive/g/Music/Movie Masterpieces/14 - 1900's Theme.ogg
/cygdrive/g/Music/Movie Masterpieces/02 - Deborah's Theme.ogg
/cygdrive/g/Music/Star Trek_ The Motion Picture [Disc 1]/01 - Ilia's Theme.ogg

However, I would like to be able to search for any folder and output the names of the files inside, for an output similar to:

/cygdrive/g/Music/Cult Themes/01 - The Avengers (1965).ogg       
/cygdrive/g/Music/Cult Themes/02 - Man In A Suitcase (1968).ogg  
/cygdrive/g/Music/Cult Themes/03 - The Saint (1962).ogg

I have access to both a Linux terminal, cygwin or Windows command prompt, and would be grateful for any solution, but if possible in one or two lines.

Edit: After receiving the a number of solutions, I've found the best solution was:

find /cygdrive/g/MUSIC -type d -iname "*theme*" -print -prune 
| xargs -d '\n' -I {} find {} -name '*.ogg'

This solution was able to complete the search the quickest, and whilst it may not be as brief as the first response, is still succinct. Thanks to all who responded!

jClark94

Posted 2012-02-20T17:08:49.680

Reputation: 125

Answers

3

The right way to process find output is not for, but to read it line by line:

find . -type d -iname '*themes*' -print -prune |
while read -r path; do
    find "$path" -name '*.ogg'
done

or

find . -type d -iname '*themes*' -print -prune |
xargs -d '\n' -I {} find {} -name '*.ogg'

or let find do it:

find . -type d -iname '*themes*' -exec find {} -name '*.ogg' \; -prune

-prune is a simple safeguard against cases where both a parent directory and a subdirectory match the -iname rule.

I skipped the traditional -print0 | xargs -d '\0' since filenames with newline characters are very, very unlikely to exist on a FAT32 filesystem.

user1686

Posted 2012-02-20T17:08:49.680

Reputation: 283 655

You could also set IFS=$'\n' and then read line, but that breaks on wildcards too when you use the filename again, so … yeah. exec would be the most concise option. – slhck – 2012-02-20T21:43:02.927

@slhck: read does not process wildcards, so I don't see how would it break when using read line. (The only place I can see is during expansion of the variable, which can be solved by double-quoting.) – user1686 – 2012-02-20T21:48:30.330

Yeah I meant expansion, it wasn't the case for your answer anyway. Just something that can be easily forgotten. – slhck – 2012-02-20T21:57:53.247

1

Here is the way to search for a dir (eg. themes), and list all the .ogg files under it (recursively):

for x in $(find . -iname "*themes*"); do find $x -iname "*.ogg"; done

I think you can customize this example for your needings, if it's not what you exactly want.

Gergely Bacso

Posted 2012-02-20T17:08:49.680

Reputation: 193

That almost works, once brackets are added for x in $( find ... ); do ..., but does not work if folders have spaces in their names. Thanks for the quick response, if I get any further I'll put the solution up. – jClark94 – 2012-02-20T19:48:35.923

1Will definitely break on spaces in file names, also beware of globbing characters when using $x again. – slhck – 2012-02-20T21:44:27.790