views:

578

answers:

5

Using Bash, how can you traverse folders within specified folder, find all files of specified file type, and every time you find a file, get full file path with file name and full file path without file name as a variables and pass them to another Bash script, execute it, and continue searching for the next file?

A: 

looks very much like homework.

find /path -type f -name "*.ext" -printf "%p:%h\n" | while IFS=: read a b
do
   # execute your bash script here
done

read the man page of find for more printf options....

ghostdog74
That doesn't seem quite right... if `%p:%h` has no spaces, `read a b` will put it all in `a` and nothing in `b`, unless you set `IFS=:`.
ephemient
yes...edited and removed the :
ghostdog74
decided to use back : since there might be files with spaces
ghostdog74
ephemient
wow, then there can be many possibilities of file names with special characters , from the way you say it. :)
ghostdog74
In UNIX, any byte sequence (possibly with a length restriction) not containing NUL ("\0") or '/' is acceptable for a file name, even if they are not printable characters.
ephemient
Beware of escape characters. Use find -print0 with xargs -0. see my more precise answer ...
neuro
+4  A: 

man find, man xrags and man file should get you started. Thanks neuro.

Sinan Ünür
I will add man xargs. See my response ...
neuro
+4  A: 

Assuming a GNU find (which is not unreasonable) you can do this using just find:

find /path -type f -name '*.ext' -exec my_cool_script \{\} \;
unwind
What is the purpose of \{\} there? Any advantage over {} or '{}'?
ustun
That is a bit of extra safety against the shell. The manual page for find states: "Both of these constructions might need to be escaped (with a `\') or quoted to protect them from expansion by the shell."
unwind
the problem with that is that find with exec do not correctly handle long list of files. I've in something like "line too long". See my detailed answer ...
neuro
@neuro: Really? `-exec ;` executes one-at-a-time, and if that command line is too long, you're pretty screwed with either `find` or `xargs`. Now, GNU findutils has had `-exec +` bugs in the past, but they should be resolved now, and the difference between `find -exec +` versus `find -print0 | xargs -0` is pretty minimal.
ephemient
@ephemient : Well I've had this sort of errors in the past, so I've used xargs since then. I probably hit some bug at the time. I used to use -exec but I found that using xargs is more readable than -exec and the escape sequences. The -print0 | xargs -0 is a magical way to handle the spaces in names particularly when you use your script in a windows/mingw/cygwin environment ...
neuro
+3  A: 

find is the way. Using xargs handle long list of files/dirs. Moreover to handle correctly names with spaces and problem like that, the best find line command I've found is :

find ${directory} -name "${pattern}" -print0 | xargs -0 ${my_command}

The trick is the find -print0 that is compatible with the xargs -0 : It replace endlines by '\0' to correctly handle spaces and escape characters. Using xargs spares you some "line too long" message when your filelist is too long.

You can use xargs with --no-run-if-empty to handle empty lists and --replace to manage complex commands.

neuro
+1  A: 

If you have GNU Parallel http://www.gnu.org/software/parallel/ installed you can do this:

find . -name '*.ext' | parallel echo {} '`dirname {}`'

Substitute echo with your favorite bash command and ext with the file extension you are looking for.

Watch the intro video for GNU Parallel to learn more: http://www.youtube.com/watch?v=OpaiGYxkSuQ

Ole Tange