kalinga
How can Iterate through all the files and directories under the current directory
Any help :wall:
------------
Kalinga.
----------------------------
#2 20 Jul 2011 15:29
flabdablet
Re: How can Iterate through all the files and directories
I generally do this by using the find command to output a list of the pathnames I want, then pipe that output into a read loop to do the processing I want.
For example, here's a snippet that renames every .JPG, JpG, .jPG, .JPEG, .jPeG etc. file in the current directory and all its subdirectories to give them all consistent lowercase .jpg extensions:
Code: Select all
find . -type f -iname '*.jpg' -o -iname '*.jpeg' -print |
while read -r name
do
mv "$name" "${name%.*}.jpg"
done
In the snippet above I'm using -type f to specify that I only want find to return the names of files, not directories; you can use -type d to get directories only, or leave the -type option out altogether to get both.
The -iname '*.jpg' part tells find to list only files whose names match case-insensitively the pattern '*.jpg' i.e. end with '.jpg' or '.JPG' or '.Jpg'. The -o -iname '*.jpeg' part extends the matching to cover all variants of '.jpeg' as well (read -o as "or").
Note that those wildcard patterns are quoted to stop the shell from expanding them; unusually for a Unix tool, we actually want find to see patterns, not filenames.
read has the -r option applied to stop it misinterpreting any \ in a filename as an escape character. Even so, read uses a newline to mark the end of input, and this code will fail if any of the filenames contains a newline character. Fortunately such filenames are very rare in practice (they break lots of shell scripts).
There are a couple of ways to use find to process a bunch of files without piping its output through a read loop. One is to use its inbuilt -exec option. Here's an example using that to copy every file from the current directory and all its subdirectories into a single directory under /tmp, effectively giving us a "flattened" directory:
Code: Select all
mkdir /tmp/foo
find . -type f -exec cp {} /tmp/foo \;
Invoking one command per file can be a bit slow when processing lots of files. Rather than use -exec, it can be a lot quicker to pipe the output of find into xargs:
Code: Select all
mkdir /tmp/foo
find . -type f -print0 | xargs -0 cp -t /tmp/foo