I have a large directory with multiple levels and tons of files. A majority (but not all) of these files are HTML files, but do not have the .html extension (a problem when copying over to Windows).

All of the HTML files have this as a first line:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

How can I, by just using a command, add the .html extension on to all files containing this string?

I have seen this SO question, but it does not rename based on whether the containings a string.

  • You could easily write a perl or shell script to do this. What shell are you using? – Peschke Mar 19 '17 at 2:03
  • What is the expected format of the filenames without the .html extension. Is it possible they may have a dot . elsewhere in their name? – MikeD Mar 19 '17 at 2:13
  • @Peschke I am using the bash shell on Ubuntu. – esote Mar 19 '17 at 2:37
  • @MikeD I cannot be sure of the extensions or names of other files. Some files will have dots in their names (some end with .jpg, for example), while others will be extensionless (on purpose, and are not HTML files). The only thing I can use to rename files is the fact that they all have the HTML header in their first line. – esote Mar 19 '17 at 2:40

Assuming all of the non-extension .html files have no extension at all, here is a simple bash script to accomplish what you need.

find . -type f ! -iname "*.html" -a ! -iname "*.htm" | while IFS= read -r file; do
    head -1 "${file}" | if grep -q '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' ; then 
        mv "${file}" "${file}.html" 

This script does the following, in order:

  1. Recursively finds all files in your current directory and child directories that do not have the .html extension.
  2. Checks to see if the found files first line is the string you provided.
  3. If the first line matches, the file is renamed to include the .html extension.
  • "Assuming all of the non-extension .html files have no extension at all": while all HTML files do not have extensions, some files (such as images or CSS files) do have extensions. Will this cause a problem when using your script? – esote Mar 19 '17 at 2:42
  • 1
    @idempotence: Only files without an extension and start with the <!DOCTYPE html ... line you provided will be affected. As long as the other files do not start with that line, they will not be renamed. I recommend running this script on a subset of files first as a test. – Peschke Mar 19 '17 at 2:45
  • Amazing! This script worked in exactly the manner I had wished. Thanks so much! – esote Mar 19 '17 at 2:56
  • Perfect! You are very welcome. Glad to help. :) – Peschke Mar 19 '17 at 2:58
  • I came up with something similar. Maybe use -iname in the find? Also, if it's possible to see .htm extensions, as well, you may want to update the find as find . -type f ! -iname "*.html" -a ! -iname "*.htm" – MikeD Mar 19 '17 at 2:58
goldn='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' \
find . -type f \
   ! -name  '*.[hH][tT][mM]'     \
   ! -name '.*.[hH][tT][mM]'     \
   ! -name  '*.[hH][tT][mM][lL]' \
   ! -name '.*.[hH][tT][mM][lL]' \
-exec sh -c '
   shift "$1"
   while case $# in 0 ) break;; esac
      read l1 < $1
      case $l1 in "$goldn" ) mv "$1" "$1.html";; esac
' 2 1 {} +

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.