Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have a bash script that search for every static file located under my server root and stores a gzipped version next to each file. I got it from http://wiki.linuxwall.info/doku.php/en:ressources:dossiers:nginx:nginx_performance_tuning

The problem is that it doesn't work with filenames with spaces, my sites don't use any right now, and I'll try it won't ever, but I'm not the only one working in the front-end so I might not be able to control it always, so I just want to make sure this script works for files that have spaces too. Hope someone can take a look and hep me fix it.

#! /bin/bash

FILETYPES=("*.html" "*.woff" "*.css" "*.jpg" "*.jpeg" "*.gif" "*.png" "*.js")
# specify a list of directories to check recursively
DIRECTORIES="/usr/share/nginx/www/"

for currentdir in $DIRECTORIES
do
   for i in "${FILETYPES[@]}"
   do
      find $currentdir -iname "$i" -exec bash -c 'PLAINFILE="{}";GZIPPEDFILE="{}".gz; \
         if [ -e "$GZIPPEDFILE" ]; \
         then   if [ `stat --printf=%Y $PLAINFILE` -gt `stat --printf=%Y $GZIPPEDFILE` ]; \
                then    echo "$GZIPPEDFILE outdated, regenerating"; \
                        gzip -9 -f -c $PLAINFILE > $GZIPPEDFILE; \
                 fi; \
         else echo "$GZIPPEDFILE is missing, creating it"; \
              gzip -9 -c $PLAINFILE > $GZIPPEDFILE; \
         fi' \;
  done
done
share|improve this question
    
No need for stat: if [[ $plainfile -nt $gzippedfile ]]. In Bash you can use single square brackets, but double square brackets are more powerful. It is recommended that you use lower case variable names by habit to avoid the possibility of name collision with shell variables. Instead of a long -exec clause with find, use -print0 and pipe it to a Bash while read -r -d '' varname loop. Quoting will be simplified and you won't be running your bash -c script repeatedly –  Dennis Williamson Aug 1 '13 at 1:11
    
for each file. Instead of using for loops for the directories use multiple arguments to find: find $directories -iname ... which works as long as there aren't spaces in the directory names. –  Dennis Williamson Aug 1 '13 at 1:12
    
Thanks @DennisWilliamson I am an absolute beginner in bash or shell scripts, after reading your link to your other post I have changed the stat part for the if [[ $plainfile -nt $gzippedfile ]], however I have no idea how to make the other changes you suggested, as I'm not familiar with it. Thanks for your help –  Raul Guichard Aug 1 '13 at 19:19
    
completely remove for currentdir in $DIRECTORIES and its associated done and change the variable from $currentdir to $directories (remembering to change the case elsewhere following my advice to use lower case variable names). Instead of doing -exec bash -c '...' use -print0 | while read -r -d '' plainfile; do gzippedfile=$plainfile.gz; if ... followed by the rest of the script (don't forget to remove the single quote and \; on the last line. On all the other lines, you can remove the final semicolon and backslash. See this paste bin –  Dennis Williamson Aug 1 '13 at 20:57
    
@DennisWilliamson Thanks, I tried your suggestion but now it doesn't do anything, I run the script and it doesn't even takes take, the console is ready again as soon as I hit enter. I copied it exactly as your pastebin –  Raul Guichard Aug 1 '13 at 21:26
show 2 more comments

1 Answer

up vote 2 down vote accepted

Quote the variables with filenames in them so they aren't interpreted as multiple arguments to a command:

#! /bin/bash

FILETYPES=("*.html" "*.woff" "*.css" "*.jpg" "*.jpeg" "*.gif" "*.png" "*.js")
# specify a list of directories to check recursively
DIRECTORIES="/usr/share/nginx/www/"

for currentdir in $DIRECTORIES
do
   for i in "${FILETYPES[@]}"
   do
      find "$currentdir" -iname "$i" -exec bash -c 'PLAINFILE="{}";GZIPPEDFILE="{}".gz; \
         if [ -e "$GZIPPEDFILE" ]; \
         then   if [ `stat --printf=%Y "$PLAINFILE"` -gt `stat --printf=%Y "$GZIPPEDFILE"` ]; \
                then    echo "$GZIPPEDFILE outdated, regenerating"; \
                        gzip -9 -f -c "$PLAINFILE" > "$GZIPPEDFILE"; \
                 fi; \
         else echo "$GZIPPEDFILE is missing, creating it"; \
              gzip -9 -c "$PLAINFILE" > "$GZIPPEDFILE"; \
         fi' \;
  done
done
share|improve this answer
    
Thank you! This worked perfectly! –  Raul Guichard Jul 31 '13 at 23:19
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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