{"id":2090,"date":"2022-12-02T15:33:57","date_gmt":"2022-12-02T15:33:57","guid":{"rendered":"https:\/\/www.antpace.com\/blog\/?p=2090"},"modified":"2025-08-25T18:02:02","modified_gmt":"2025-08-25T18:02:02","slug":"identify-unused-image-files-in-a-code-project","status":"publish","type":"post","link":"https:\/\/www.antpace.com\/blog\/identify-unused-image-files-in-a-code-project\/","title":{"rendered":"Identify Unused Image Files in a Code Project"},"content":{"rendered":"<p>I wrote a script to list (and optionally delete) the image files it finds in a directory that are not referenced any where.\u00a0 I specified a single sub-directory at a time. If you do the entire project it may take long to complete.<\/p>\n<pre>#!\/bin\/bash\n\nPROJECT_DIR=\"$PWD\"\nIMAGE_DIR=\"$PWD\"\n\nDELETE_FLAG=false\n\n# Check for -d (delete) flag\nif [[ $1 == \"-d\" ]]; then\n    DELETE_FLAG=true\nfi\n\n# Find all image files\nfind $IMAGE_DIR -type f \\( -iname \\*.png -o -iname \\*.jpg -o -iname \\*.jpeg -o -iname \\*.gif -o -iname \\*.webp -o -iname \\*.svg -o -iname \\*.ico \\) | while read img_file; do\n    # Extract the basename of the image file\n    img_basename=$(basename \"$img_file\")\n\n    # Search for it in the project, excluding .zip files and .git directories\n    result=$(grep -ril --exclude=*.zip --exclude-dir=.git \"$img_basename\" \"$PROJECT_DIR\")\n\n    # If not found, print it or delete it based on flag\n    if [ -z \"$result\" ]; then\n        echo \"Unused image: $img_file\"\n        if $DELETE_FLAG; then\n            rm \"$img_file\"\n            echo \"Deleted: $img_file\"\n        fi\n    fi\ndone\n\n<\/pre>\n<p>Be sure to edit the code to include the image file types that you want to target. Make the file executable before trying to use it:<\/p>\n<pre>chmod +x find_unused_images.sh\n<\/pre>\n<p>Run the script (without deletion)<\/p>\n<pre>.\/find_unused_images.sh<\/pre>\n<p>To run the script with the delete functionality:<\/p>\n<pre>.\/find_unused_images.sh -d\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2083\" src=\"https:\/\/www.antpace.com\/blog\/wp-content\/uploads\/2023\/10\/unused-images.png\" alt=\"Find unused images in a project\" width=\"884\" height=\"560\" \/><\/p>\n<p>In an early version, my script was leaving behind files that appeared to be completely unreferenced in the code base (I checked manually by searching the project via IDE). To troubleshoot, I ran <code>grep<\/code> from the command line:<\/p>\n<pre>grep -ril \"experienceLogo2.png\" \"$PWD\"<\/pre>\n<p>It turned out that those files were referenced in a zip file and in git objects (and therefore considered not unused). I fixed this bug by adding the <em>flags &#8211;exclude=*.zip &#8211;exclude-dir=.git<\/em> to my <code>grep<\/code> command in <em>find_unused_images.sh<\/em>.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2084\" src=\"https:\/\/www.antpace.com\/blog\/wp-content\/uploads\/2023\/10\/grep.png\" alt=\"grep to find a file reference within a directory\" width=\"972\" height=\"142\" \/><br \/>\nI had lots of unused stock images and old designs that felt good to purge. Now with generative image AI, I know I could create assets easily as I need them in the future.<\/p>\n<p>I used this script during a project to upgrade my website to use next generation file formats. If you liked this post, <a href=\"https:\/\/www.antpace.com\/blog\/managing-content-for-an-art-website\/\">read another one where I discuss managing graphic assets for a web project<\/a>.<\/p>\n<h2>Update<\/h2>\n<h3 class=\"entry-title\">Identify any unused files in a code project<\/h3>\n<p>This code can be changed to search for any kind of file. Here&#8217;s an updated version I used to see if some old Bootstrap files were being used any where:<\/p>\n<pre>#!\/bin\/bash\n\nPROJECT_DIR=\"$PWD\"\nFILE_DIR=\"$PWD\/css\"\n\nDELETE_FLAG=false\n\n# Check for -d (delete) flag\nif [[ $1 == \"-d\" ]]; then\n    DELETE_FLAG=true\nfi\n\n# Find all image files\n# find $FILE_DIR -type f \\( -iname \\*.png -o -iname \\*.jpg -o -iname \\*.jpeg -o -iname \\*.gif -o -iname \\*.webp -o -iname \\*.svg -o -iname \\*.ico \\) | while read my_file; do\nfind $FILE_DIR -type f \\( -iname \\*.css -o -iname \\*.js \\) | while read my_file; do\n    # Extract the basename of the image file\n    file_basename=$(basename \"$my_file\")\n\n    # Search for it in the project, excluding .zip files and .git directories and .xml directories\n    result=$(grep -ril --exclude=*.zip --exclude-dir=.git --exclude=*.xml \"$file_basename\" \"$PROJECT_DIR\")\n\n    # If not found, print it or delete it based on flag\n    if [ -z \"$result\" ]; then\n        echo \"Unused file: $my_file\"\n        if $DELETE_FLAG; then\n            rm \"$my_file\"\n            echo \"Deleted: $my_file\"\n        fi\n    fi\ndone<\/pre>\n<p>This didn&#8217;t work perfectly. I had to add an exclusion condition for .xml files because my WordPress blog archive files were being highlighted in the search. (EOD, I ended up zipping the few .xml archive files anyway. I also keep them on <a href=\"https:\/\/www.antpace.com\/blog\/automatic-mysql-dump-to-s3\/\">an S3 bucket, but I enjoy redundancy<\/a>.)<\/p>\n<p>The file name &#8220;bootstrap.css&#8221; was being found in its own file.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2215\" src=\"https:\/\/www.antpace.com\/blog\/wp-content\/uploads\/2022\/12\/bootstrap-reference.png\" alt=\"Bootstrap source code\" width=\"758\" height=\"242\" \/><\/p>\n<p>This, at least, gave me enough confidence to just delete the files manually. I can&#8217;t call this a perfect tool (and I don&#8217;t think it would scale well), but it is a utility for a practical use-case.<\/p>\n<p>I saw other examples of it acting funny. For instance, I had an old stock photo file named &#8216;5.jpg&#8217;. It was coming up as being used in the project because, for some reason, that string was found in\u00a0<em>another image file<\/em> &#8211; &#8216;jimmy.webp&#8217;.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2218\" src=\"https:\/\/www.antpace.com\/blog\/wp-content\/uploads\/2022\/12\/image-search-cli.png\" alt=\"using grep to search image file names\" width=\"729\" height=\"97\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wrote a script to list (and optionally delete) the image files it finds in a directory that are not referenced any where.\u00a0 I specified a single sub-directory at a time. If you do the entire project it may take long to complete. #!\/bin\/bash PROJECT_DIR=&#8221;$PWD&#8221; IMAGE_DIR=&#8221;$PWD&#8221; DELETE_FLAG=false # Check for -d (delete) flag if [[ &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.antpace.com\/blog\/identify-unused-image-files-in-a-code-project\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Identify Unused Image Files in a Code Project&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":3257,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[22,55,140],"class_list":["post-2090","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-development","tag-cli","tag-frontend","tag-web-development"],"_links":{"self":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts\/2090","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/comments?post=2090"}],"version-history":[{"count":1,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts\/2090\/revisions"}],"predecessor-version":[{"id":3258,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/posts\/2090\/revisions\/3258"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/media\/3257"}],"wp:attachment":[{"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/media?parent=2090"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/categories?post=2090"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.antpace.com\/blog\/wp-json\/wp\/v2\/tags?post=2090"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}