Bash Tips: Find and Iterate through Files in a Folder

A fast and flexible automation pattern

March 1, 2023

Another Short Introduction to Bash

The standard way of interacting with a computer is through the graphical user interface – GUI for short. Another method that predates the GUI is the command line, where the user enters text prompts which tell the computer what to do. Common operations include navigating the file system, reading and writing files, and running programs. These basic operations are easily accomplished in the GUI but the command line is still useful, especially for automation.

A common pattern in useful automations is finding and operating on a specific set of files within a folder. For example, say you have an inbox folder full of documents and you want to move each PDF to different folder, while keeping the rest of the files unchanged. Such a task quickly grows tedious to do in the GUI but remains simple when using the command line, regardless of there being 10 or 10,000 PDFs.

Step 1: Find Files

Bash has a 'find' command which takes as input 2 parameters: a directory and a pattern, then ouputs every matching file contained in the directry (also searching through subdirectories). The following snippet will output the list of PDFs that exist in the current directory.

find . -name "*.pdf";

Step 2: Iterate through files

Like most languages, Bash makes it easy to iterate through a list. Here’s a snippet that takes in the results of the find command and iterates through it, in this case printing out each filename.

for file in `find . -name "*.pdf"`; do
  echo $file;

Replacing the echo line, we can use the filename in other ways. Let’s move each file to a directory named pdfs, completing the example automation.

for file in `find . -name "*.pdf"`; do
  mv $file ../pdfs/;

More Examples

Delete all .DS_Store files

for file in `find . -name ".DS_Store"`; do
  rm $file;

Put all logs into a single log file

echo > logs.txt # create or empty the log file

for file in `find . -name "*log.txt"`; do
  echo $file >> logs.txt; # append the filename
  cat $file >> logs.txt;  # log contents
  echo >> logs.txt;       # new line

Create a darkened version of each png

for file in `find . -name "*.png"`; do
  # file: daisy.png -> out: darkened_daisy.png
  out=`dirname $file`"/darkened_"`basename $file`;
  convert -brightness-contrast -30x0 $file $out;

Create a jpg of each png

for file in `find . -name "*.png"`; do
  convert $file ${file/png/jpg};

Upload all json files to an S3 bucket

for file in `find . -name "*.json"`; do
  aws s3 cp $file s3://json/`basename $file`;