Find and Act Quickly on Files

Today, I had a directory of files, and I wanted to copy a subset of those files into another directory, following the exact same directory structure. More specifically, I had a directory structure that looked like this:

> ls dir

In my case, I wanted to copy all the .1 files alone into another directory, such that I end up with:

> ls working_dir

Copying them by hand wasn’t an option, given that there were over 300 of these files spread out across these subdirectories.

I’ve really love the fd tool as a replacement for find due to its speed and performance. Initially, I was trying to use a combination of fd and shell scripting to do what I want. This worked initially, but I found edge cases where it didn’t work the way I expected it to. At that point, I remembered that fd supports running commands on the file results. I didn’t realize just how much time this would save. I ended up accomplishing the above by using the following 2 commands:

fd -e 1 -x mkdir -p working_dir/{//}
fd -e 1 -x cp {} working_dir/{}
fd -e 1 -x rm

Let’s break this down:

The second command uses {}, a placeholder which will be replaced by the full path of the search result. The third command erases those files. Note the missing {}, since if there is no placeholder, fd will automatically add {} at the end.

Consequently, these commands translate each search result into a mkdir and then a cp to accomplish what we want, followed by a deletion to remove the file - i.e.:

> 2020/06/directory/file.mp3.1
mkdir -p destination_directory/2020/06/directory
cp 2020/06/directory/file.mp3.1 destination_directory/2020/06/directory/file.mp3.1
rm 2020/06/directory/file.mp3.1

Awesome! There are also other placeholders, such as {.} (file path without the extension), {/} (file name without the path), and {/.} (file without the path and without the extension).