I recently had to replace hundreds of logos across multiple pages in a client project. The client had updated their partner logos and they appeared in various pages of the site. One great thing about file-based CMSs like Kirby is that we can use simple command line tools to manage our content. While I often use search & replace for text changes, this was the first time I automated file replacements.
The challenge
Let’s say you have a folder structure like this and you want to replace the old partner logos with updated versions:
Alternative text description for the folder structure
The following code block shows a folder structure. The content folder contains a projects folder and an about folder. Inside projects are two subfolders: project-a containing logo-a.png, and project-b containing logo-b.png. The about folder contains another copy of logo-a.png. Separately, there’s a new-logos folder containing the updated versions of both logo-a.png and logo-b.png.📁 content/
├── 📁 projects/
│ ├── 📁 project-a/
│ │ └── 🖼️ logo-a.png
│ └── 📁 project-b/
│ └── 🖼️ logo-b.png
└── 📁 about/
└── 🖼️ logo-a.png
📁 new-logos/
├── 🖼️ logo-a.png
└── 🖼️ logo-b.png
The solution
Before running commands like this, remember to back up your content folder.
Shit happens, and you don’t want to lose your original files.
Here’s a simple bash command that does the job:
find content -type f -name "*.png" -exec sh -c 'cp -v new-logos/$(basename {}) {}' \;
It will return a log like this for the folder structure above:
new-logos/logo-a.png -> content/projects/project-a/logo-a.png
new-logos/logo-a.png -> content/about/partners/logo-a.png
new-logos/logo-b.png -> content/projects/project-b/logo-b.png
new-logos/logo-b.png -> content/about/partners/logo-b.png
Let’s break it down:
find content
Start searching in the content directory-type f
Look for files (not folders)-name "*.png"
Match files ending in png-exec sh -c
Run a shell command for each file foundbasename {}
Extract just the filename from the full pathcp -v
Copy command with verbose outputnew-logos/$(basename {})
Use the extracted filename to find the new version{}
The original file’s full path (where to copy to)\;
End the -exec command
For example, when the command finds content/projects/project-a/logo-a.png
:
- Extracted basename:
logo-a.png
- This creates the source path
new-logos/logo-a.png
- The file is copied to the original location
content/projects/project-a/logo-a.png
If you want to do a dry run to see what files would be replaced, you can use this:
find content -type f -name "*.png" -exec sh -c 'echo "new-logos/$(basename {}) -> {}"' \;
Different file types
The command only handles .png
files because of the -name "*.png"
part. You can adjust it or remove it altogether to replace any file that has a matching name:
find content -type f -exec sh -c 'cp -v new-logos/$(basename {}) {}' \;
Just be careful with this version – it will try to replace every file in your content folder that has a matching filename in new-logos/
, regardless of its type.