From the “Terminal,” I’m wondering how can I convert all “x”s to “y”s
in filenames for a specific directory on Mac OS X? Note that “x” means
just anything and with “y” simply being a space.
I’d like to do this recursively, handling all sub-directories rather
than only one folder at a time.
Adapting the some the basic sed
concept that @meatspace refers to in his comment (which is located on this page) and adding find
into the mix I came up with this script:
find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f |\
while read FULL_ITEM_PATH
do
FILE_DIRNAME=$(dirname "${FULL_ITEM_PATH}");
FILE_BASENAME=$(basename "${FULL_ITEM_PATH}");
mv "${FILE_DIRNAME}"/"${FILE_BASENAME}" "${FILE_DIRNAME}"/"$(echo $FILE_BASENAME | sed -e 's/_/ /g')";
done
That will use find
to find all files from the current directory you are in—including child directories/files—and then search for underscores in filenames (_
) and change them to spaces (
) as desired. The script ignores “dot files”/“invisible files” like .DS_Store
via -prune -o -not -name '.*'
and then the core logic only acts on the actual filename—not the directory name—by separating the file basename from the directory name.
I created a test directory tree on my Mac OS X 10.9.5 (Mavericks) machine with files that contain underscores (_
) in their names—with some nested in a child directory—like this:
./foo_bar
./foo_bar_two
./foo_bar_two_three
./foo_bar_two_three_bleagh.txt
./nested/foo_bar
./nested/foo_bar_two
./nested/foo_bar_two_three
./nested/foo_bar_two_three_bleagh.txt
./nested_foo/foo_bar
./nested_foo/foo_bar_two
./nested_foo/foo_bar_two_three
./nested_foo/foo_bar_two_three_bleagh.txt
Then I ran that script and they were all automatically changed to use spaces (
) as desired like this:
./foo bar
./foo bar two
./foo bar two three
./foo bar two three bleagh.txt
./nested/foo bar
./nested/foo bar two
./nested/foo bar two three
./nested/foo bar two three bleagh.txt
./nested_foo/foo bar
./nested_foo/foo bar two
./nested_foo/foo bar two three
./nested_foo/foo bar two three bleagh.txt
While the script works, if you want to do a simple “dry run” to see what files the script would act on replace the mv
command to echo
like this:
find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f |\
while read FULL_ITEM_PATH
do
FILE_DIRNAME=$(dirname "${FULL_ITEM_PATH}");
FILE_BASENAME=$(basename "${FULL_ITEM_PATH}");
echo "${FILE_DIRNAME}"/"${FILE_BASENAME}" "${FILE_DIRNAME}"/"$(echo $FILE_BASENAME | sed -e 's/_/ /g')";
done
The nice thing about using echo
to debug is you can also see exactly what is happening in the core of your script. So while I have coded this script to fit the exact needs as specified in this question, feel free to experiment with it to adapt it to newer needs/ideas if they come up.