title: Safe rm -rf function in shell script
body: <p>This question is similar to <a href="https://stackoverflow.com/questions/373156/what-is-the-safest-way-to-empty-a-directory-in-nix">What is the safest way to empty a directory in *nix?</a></p>
  
  <p>I'm writing bash script which defines several path constants and will use them for file and directory manipulation (copying, renaming and deleting). Often it will be necessary to do something like:</p>
  
  <pre><code>rm -rf "/${PATH1}"
  rm -rf "${PATH2}/"*
  </code></pre>
  
  <p>While developing this script I'd want to protect myself from mistyping names like PATH1 and PATH2 and avoid situations where they are expanded to empty string, thus resulting in wiping whole disk. I decided to create special wrapper:</p>
  
  <pre><code>rmrf() {
      if [[ $1 =~ "regex" ]]; then
          echo "Ignoring possibly unsafe path ${1}"
          exit 1
      fi
  
      shopt -s dotglob
      rm -rf -- $1
      shopt -u dotglob
  }
  </code></pre>
  
  <p>Which will be called as:</p>
  
  <pre><code>rmrf "/${PATH1}"
  rmrf "${PATH2}/"*
  </code></pre>
  
  <p>Regex (or sed expression) should catch paths like "*", "/*", "/**/", "///*" etc. but allow paths like "dir", "/dir", "/dir1/dir2/", "/dir1/dir2/*".  Also I don't know how to enable shell globbing in case like "/dir with space/*". Any ideas?</p>
  
  <p>EDIT: this is what I came up with so far:</p>
  
  <pre><code>rmrf() {
      local RES
      local RMPATH="${1}"
      SAFE=$(echo "${RMPATH}" | sed -r 's:^((\.?\*+/+)+.*|(/+\.?\*+)+.*|[\.\*/]+|.*/\.\*+)$::g')
      if [ -z "${SAFE}" ]; then
          echo "ERROR! Unsafe deletion of ${RMPATH}"
          return 1
      fi
  
      shopt -s dotglob
      if [ '*' == "${RMPATH: -1}" ]; then
          echo rm -rf -- "${RMPATH/%\*/}"*
          RES=$?
      else
          echo rm -rf -- "${RMPATH}"
          RES=$?
      fi
      shopt -u dotglob
  
      return $RES
  }
  </code></pre>
  
  <p>Intended use is (note an asterisk <em>inside</em> quotes):</p>
  
  <pre><code>rmrf "${SOMEPATH}"
  rmrf "${SOMEPATH}/*"
  </code></pre>
  
  <p>where $SOMEPATH is not system or /home directory (in my case all such operations are performed on filesystem mounted under /scratch directory).</p>
  
  <p>CAVEATS:</p>
  
  <ul>
  <li>not tested very well</li>
  <li>not intended to use with paths possibly containing '..' or '.'</li>
  <li>should not be used with user-supplied paths</li>
  <li>rm -rf with asterisk probably can fail if there are too many files or directories inside $SOMEPATH (because of limited command line length) - this can be fixed with 'for' loop or 'find' command</li>
  </ul>