<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>AskApache &#187; Search Results  &#187;  shell-scripts</title>
	<atom:link href="http://www.askapache.com/search/shell-scripts/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.askapache.com</link>
	<description>Advanced Web Development</description>
	<lastBuildDate>Thu, 26 Apr 2012 11:29:28 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Actual Htaccess Files from My Server</title>
		<link>http://www.askapache.com/htaccess/real-world-htaccess-files.html</link>
		<comments>http://www.askapache.com/htaccess/real-world-htaccess-files.html#comments</comments>
		<pubDate>Sat, 17 Apr 2010 15:06:22 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Htaccess]]></category>

		<guid isPermaLink="false">http://www.askapache.com/?p=4357</guid>
		<description><![CDATA[<pre>#### No https except to wp-admin -
# If the request is empty ( implies fopen or normal file access by a php script )
RewriteCond %{THE_REQUEST} ^$ [OR]
&#160;
# OR if the request if for wp-admin or wp-login.php
RewriteCond %{REQUEST_URI} ^/(wp-admin&#124;wp-login\.php).*$ [NC,OR]
&#160;
# OR if the Referer is https
RewriteCond %{HTTP_REFERER} ^https://www.askapache.com/.*$ [NC]
&#160;
# THEN skip the following rule, basically all this does is force https or badhost to be redirected
# BUT because of the above 3 rewritecond&#039;s, this won&#039;t break poorly written admin scripts
RewriteRule .* - [S=1]
&#160;
RewriteCond %{HTTPS} =on [OR]
RewriteCond %{HTTP_HOST} !^www\.askapache\.com$ [NC]
RewriteRule .* http://www.askapache.com%{REQUEST_URI} [R=301,L]
&#160;
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(wp-admin/.*&#124;wp-login\.php.*)\ HTTP/ [NC]
RewriteCond %{HTTPS} !=on
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]</pre>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/htaccess/real-world-htaccess-files.html"></a><a href="http://www.askapache.com/htaccess/real-world-htaccess-files.html"><cite>AskApache.com</cite></a></p><p>I was going through some backups from years ago, and ran:</p>
<pre>locate .htaccess | xargs -I&#039;{}&#039; cat &#039;{}&#039; &gt;&gt; master-htaccesser.txt</pre>
<p>My site is named after reading source code because that is what helps me the most when I'm trying to learn something unusually difficult.   Just like functions and aliases, it is very helpful to have cheatsheets for common commands.. not much is better than real-world examples.  Unfortunately because this was compiled from hundreds of htaccess files on multiple hosts and platforms, and due to the concatenation, it's not organized.</p>

<p>Normally I would not publish something like this, who knows how much unreleased tricks I forgot about..  but in order to say thanks to all those working for open-source, the FSF, and to all those who don't steal content, and to all the incredible authors who shared with me (I twitter most of what I find, and follow my favs), here ya go..</p>


<p class="cnote"><strong>ATTN:</strong> Please let me know if this is total junk or not, this is around 1/500th of my master-htaccesser.txt file.. and I'd be happy to post more if it helps..</p>

<h2>Checking for Cookie</h2>
<p>Used this to stop mp3-scrapers.. checks for a cookie ending in MP3P=02357</p>
<pre>Options -Indexes
RewriteEngine On
RewriteCond %{HTTP_COOKIE} !^.*MP3P=([0-9]+).* [NC]
RewriteRule .* - [F,L]</pre>

<h2>Setting Environment Var if Proxied</h2>
<pre>RewriteEngine On
RewriteRule "\.(gif|png|jpg)$" "-" [ENV=proxied_image:1]
RewriteCond "%{ENV:proxied_image}" "!1"
RewriteRule "^" "-" [ENV=proxied_other:1]</pre>

<h2>nokeepalive for ErrorDocs and Abusers</h2>
<pre>Options SymLinksIfOwnerMatch IncludesNOEXEC
AddOutputFilter Includes html
SetEnv nokeepalive
Order Allow,Deny
Allow from all
# 1 YEAR
&lt;filesMatch "\.(js|css)$"&gt;
Header unset Pragma
FileETag None
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified
Header unset Last-Modified
Header unset ETag
&nbsp;
SetOutputFilter DEFLATE
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/filesMatch&gt;
SecFilterEngine Off
&nbsp;
# 1 YEAR
&lt;filesMatch "\.(js|css)$"&gt;
Header unset Pragma
FileETag None
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified
Header unset Last-Modified
Header unset ETag
&nbsp;
SetOutputFilter DEFLATE
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/filesMatch&gt;</pre>








<h2>Unreleased Tests for AskApache Password Protection</h2>
<pre># +ASKAPACHE PASSPRO 4.6.6
#######################################################
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# +APRO SIDS
# +SID 21030002
Order Deny,Allow
Deny from All
Satisfy Any
AuthType Digest
AuthName "Protected By AskApache"
AuthDigestDomain / http://www.askapache.com/
AuthDigestFile /home/.greer/askapache/sites/askapache.com/.htpasswda3
Require valid-user
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|mp3|mpg|mp4|mov|wav|wmv|png|gif|swf|css|js)$"&gt;
Allow from All
&lt;/filesMatch&gt;
&lt;filesMatch "(async-upload|admin-ajax)\.php$"&gt;
&lt;ifModule mod_security.c&gt;
SecFilterEngine Off
&lt;/ifModule&gt;
Allow from All
&lt;/filesMatch&gt;
# -SID 21030002
# -APRO SIDS
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
#######################################################
# -ASKAPACHE PASSPRO 4.6.6
&nbsp;
# +ASKAPACHE PASSPRO 4.6.6
#######################################################
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# +APRO SIDS
# +SID Test
ErrorDocument 401 /wp-content/askapache/test.gif
ErrorDocument 403 /wp-content/askapache/test.gif
ErrorDocument 404 /wp-content/askapache/test.gif
ErrorDocument 500 /wp-content/askapache/test.gif
ServerSignature On
&lt;ifModule mod_alias.c&gt;
RedirectMatch 305 ^.*modaliastest$ http://www.askapache.com
&lt;/ifModule&gt;
&lt;ifModule mod_rewrite.c&gt;
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} modrewritetest [NC]
RewriteRule .* http://www.askapache.com [R=307,L]
&lt;/ifModule&gt;
&lt;files modsec_check.gif&gt;
&lt;ifModule mod_security.c&gt;
SetEnv MODSEC_ENABLE On
SecFilterEngine On
SecFilterDefaultAction "nolog,noauditlog,pass"
SecAuditEngine Off
SecFilterInheritance Off
SecFilter modsecuritytest "deny,nolog,noauditlog,status:503"
Deny from All
&lt;/ifModule&gt;
&lt;/files&gt;
&lt;files basic_auth_test.gif&gt;
AuthType Basic
AuthName "askapache test"
AuthUserFile /home/.greer/askapache/sites/askapache.com/htdocs/wp-content/askapache/.htpasswd-basic
Require valid-user
&lt;/files&gt;
&lt;files digest_check.gif&gt;
AuthType Digest
AuthName "askapache test"
AuthDigestDomain /wp-content/askapache/ http://www.askapache.com/wp-content/askapache/
AuthUserFile /home/.greer/askapache/sites/askapache.com/htdocs/wp-content/askapache/.htpasswd-digest
Require none
&lt;/files&gt;
&lt;files authuserfile_test.gif&gt;
AuthType Digest
AuthName "askapache test"
AuthDigestDomain /wp-content/askapache/ http://www.askapache.com/wp-content/askapache/
AuthUserFile /home/.greer/askapache/sites/askapache.com/htdocs/wp-content/askapache/.htpasswd-digest
Require valid-user
&lt;/files&gt;
&lt;files authdigestfile_test.gif&gt;
AuthType Digest
AuthName "askapache test"
AuthDigestDomain /wp-content/askapache/ http://www.askapache.com/wp-content/askapache/
AuthDigestFile /home/.greer/askapache/sites/askapache.com/htdocs/wp-content/askapache/.htpasswd-digest
Require valid-user
&lt;/files&gt;
# -SID Test
# -APRO SIDS
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
#######################################################
# -ASKAPACHE PASSPRO 4.6.6</pre>
















<h2>Warming up to the really advanced tests</h2>
<pre>Options +ExecCGI
Order Deny,Allow
Deny from All
Allow from 208.113.134.190 64.111.114.111 208.113.134.203 208.113.152.201 env=REDIRECT_STATUS
Satisfy Any
Options +FollowSymLinks
AddHandler application/x-httpd-php .php
&nbsp;
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} !^tyy+$ [NC]
RewriteCond %{REMOTE_USER} ^(.+)$
RewriteRule ^(.*)$ $1/-%1 [R=302,L]
Options +ExecCGI +FollowSymLinks
DirectoryIndex index.php
ErrorDocument 404 /cgi-bin/pro/index.php
&nbsp;
AuthType Digest
AuthName "AskApache Pro"
AuthDigestFile /home/askapache/sites/askapache.com/.htpasswd-pro
AuthDigestDomain /cgi-bin/pro/ http://www.askapache.com/cgi-bin/pro/ https://www.askapache.com/cgi-bin/pro/
Require user askapacheDirectoryIndex p.php
ErrorDocument 403 /cgi-bin/p/p.php
ErrorDocument 401 /cgi-bin/p/p.php
ErrorDocument 500 /cgi-bin/p/p.php
ErrorDocument 503 /cgi-bin/p/p.php
&nbsp;
RewriteEngine On
RewriteBase /
RewriteRule .* - [E=INFO_API_VERSION:%{API_VERSION}]
RewriteRule .* - [E=INFO_AUTH_TYPE:%{AUTH_TYPE}]
RewriteRule .* - [E=INFO_CONTENT_LENGTH:%{CONTENT_LENGTH}]
RewriteRule .* - [E=INFO_CONTENT_TYPE:%{CONTENT_TYPE}]
RewriteRule .* - [E=INFO_DOCUMENT_ROOT:%{DOCUMENT_ROOT}]
RewriteRule .* - [E=INFO_GATEWAY_INTERFACE:%{GATEWAY_INTERFACE}]
RewriteRule .* - [E=INFO_HTTPS:%{HTTPS}]
RewriteRule .* - [E=INFO_HTTP_ACCEPT:%{HTTP:Accept}]
RewriteRule .* - [E=INFO_HTTP_ACCEPT_LANGUAGE:%{HTTP:Accept-Language}]
RewriteRule .* - [E=INFO_HTTP_ACCEPT_ENCODING:%{HTTP:Accept-Encoding}]
RewriteRule .* - [E=INFO_HTTP_ACCEPT_CHARSET:%{HTTP:Accept-Charset}]
RewriteRule .* - [E=INFO_HTTP_CACHE_CONTROL:%{HTTP:Cache-Control}]
RewriteRule .* - [E=INFO_HTTP_CONNECTION:%{HTTP:Connection}]
RewriteRule .* - [E=INFO_HTTP_COOKIE:%{HTTP_COOKIE}]
RewriteRule .* - [E=INFO_HTTP_FORWARDED:%{HTTP_FORWARDED}]
RewriteRule .* - [E=INFO_HTTP_HOST:%{HTTP_HOST}]
RewriteRule .* - [E=INFO_HTTP_KEEP_ALIVE:%{HTTP_KEEP_ALIVE}]
RewriteRule .* - [E=INFO_HTTP_PROXY_CONNECTION:%{HTTP_PROXY_CONNECTION}]
RewriteRule .* - [E=INFO_HTTP_REFERER:%{HTTP:Referer}]
RewriteRule .* - [E=INFO_HTTP_USER_AGENT:%{HTTP_USER_AGENT}]
RewriteRule .* - [E=INFO_IS_SUBREQ:%{IS_SUBREQ}]
RewriteRule .* - [E=INFO_ORIG_PATH_INFO:%{ORIG_PATH_INFO}]
RewriteRule .* - [E=INFO_ORIG_PATH_TRANSLATED:%{ORIG_PATH_TRANSLATED}]
RewriteRule .* - [E=INFO_ORIG_SCRIPT_FILENAME:%{ORIG_SCRIPT_FILENAME}]
RewriteRule .* - [E=INFO_ORIG_SCRIPT_NAME:%{ORIG_SCRIPT_NAME}]
RewriteRule .* - [E=INFO_PATH:%{PATH}]
RewriteRule .* - [E=INFO_PATH_INFO:%{PATH_INFO}]
RewriteRule .* - [E=INFO_QUERY_STRING:%{QUERY_STRING}]
RewriteRule .* - [E=INFO_REDIRECT_QUERY_STRING:%{REDIRECT_QUERY_STRING}]
RewriteRule .* - [E=INFO_REDIRECT_REMOTE_USER:%{REDIRECT_REMOTE_USER}]
RewriteRule .* - [E=INFO_REDIRECT_STATUS:%{REDIRECT_STATUS}]
RewriteRule .* - [E=INFO_REDIRECT_URL:%{REDIRECT_URL}]
RewriteRule .* - [E=INFO_REMOTE_ADDR:%{REMOTE_ADDR}]
RewriteRule .* - [E=INFO_REMOTE_HOST:%{REMOTE_HOST}]
RewriteRule .* - [E=INFO_REMOTE_IDENT:%{REMOTE_IDENT}]
RewriteRule .* - [E=INFO_REMOTE_PORT:%{REMOTE_PORT}]
RewriteRule .* - [E=INFO_REMOTE_USER:%{REMOTE_USER}]
RewriteRule .* - [E=INFO_REQUEST_FILENAME:%{REQUEST_FILENAME}]
RewriteRule .* - [E=INFO_REQUEST_METHOD:%{REQUEST_METHOD}]
RewriteRule .* - [E=INFO_REQUEST_URI:%{REQUEST_URI}]
RewriteRule .* - [E=INFO_REDIRECT_REQUEST_URI:%{REDIRECT_REQUEST_URI}]
RewriteRule .* - [E=INFO_SCRIPT_FILENAME:%{SCRIPT_FILENAME}]
RewriteRule .* - [E=INFO_SCRIPT_GROUP:%{SCRIPT_GROUP}]
RewriteRule .* - [E=INFO_SCRIPT_NAME:%{SCRIPT_NAME}]
RewriteRule .* - [E=INFO_SCRIPT_URI:%{SCRIPT_URI}]
RewriteRule .* - [E=INFO_SCRIPT_URL:%{SCRIPT_URL}]
RewriteRule .* - [E=INFO_SCRIPT_USER:%{SCRIPT_USER}]
RewriteRule .* - [E=INFO_SERVER_ADDR:%{SERVER_ADDR}]
RewriteRule .* - [E=INFO_SERVER_ADMIN:%{SERVER_ADMIN}]
RewriteRule .* - [E=INFO_SERVER_NAME:%{SERVER_NAME}]
RewriteRule .* - [E=INFO_SERVER_PORT:%{SERVER_PORT}]
RewriteRule .* - [E=INFO_SERVER_PROTOCOL:%{SERVER_PROTOCOL}]
RewriteRule .* - [E=INFO_SERVER_SIGNATURE:%{SERVER_SIGNATURE}]
RewriteRule .* - [E=INFO_SERVER_SOFTWARE:%{SERVER_SOFTWARE}]
RewriteRule .* - [E=INFO_THE_REQUEST:%{THE_REQUEST}]
RewriteRule .* - [E=INFO_TIME:%{TIME}]
RewriteRule .* - [E=INFO_TIME_DAY:%{TIME_DAY}]
RewriteRule .* - [E=INFO_TIME_HOUR:%{TIME_HOUR}]
RewriteRule .* - [E=INFO_TIME_MIN:%{TIME_MIN}]
RewriteRule .* - [E=INFO_TIME_MON:%{TIME_MON}]
RewriteRule .* - [E=INFO_TIME_SEC:%{TIME_SEC}]
RewriteRule .* - [E=INFO_TIME_WDAY:%{TIME_WDAY}]
RewriteRule .* - [E=INFO_TIME_YEAR:%{TIME_YEAR}]
RewriteRule .* - [E=INFO_TZ:%{TZ}]
RewriteRule .* - [E=INFO_UNIQUE_ID:%{UNIQUE_ID}]
&nbsp;
RequestHeader set INFO_API_VERSION "%{INFO_API_VERSION}e"
RequestHeader set INFO_AUTH_TYPE "%{INFO_AUTH_TYPE}e"
RequestHeader set INFO_CONTENT_LENGTH "%{INFO_CONTENT_LENGTH}e"
RequestHeader set INFO_CONTENT_TYPE "%{INFO_CONTENT_TYPE}e"
RequestHeader set INFO_DOCUMENT_ROOT "%{INFO_DOCUMENT_ROOT}e"
RequestHeader set INFO_GATEWAY_INTERFACE "%{INFO_GATEWAY_INTERFACE}e"
RequestHeader set INFO_HTTPS "%{INFO_HTTPS}e"
RequestHeader set INFO_HTTP_ACCEPT "%{INFO_HTTP_ACCEPT}e"
RequestHeader set INFO_HTTP_ACCEPT_LANGUAGE "%{INFO_HTTP_ACCEPT_LANGUAGE}e"
RequestHeader set INFO_HTTP_ACCEPT_ENCODING "%{INFO_HTTP_ACCEPT_ENCODING}e"
RequestHeader set INFO_HTTP_ACCEPT_CHARSET "%{INFO_HTTP_ACCEPT_CHARSET}e"
RequestHeader set INFO_HTTP_CACHE_CONTROL "%{INFO_HTTP_CACHE_CONTROL}e"
RequestHeader set INFO_HTTP_CONNECTION "%{INFO_HTTP_CONNECTION}e"
RequestHeader set INFO_HTTP_COOKIE "%{INFO_HTTP_COOKIE}e"
RequestHeader set INFO_HTTP_FORWARDED "%{INFO_HTTP_FORWARDED}e"
RequestHeader set INFO_HTTP_HOST "%{INFO_HTTP_HOST}e"
RequestHeader set INFO_HTTP_KEEP_ALIVE "%{INFO_HTTP_KEEP_ALIVE}e"
RequestHeader set INFO_HTTP_PROXY_CONNECTION "%{INFO_HTTP_PROXY_CONNECTION}e"
RequestHeader set INFO_HTTP_REFERER "%{INFO_HTTP_REFERER}e"
RequestHeader set INFO_HTTP_USER_AGENT "%{INFO_HTTP_USER_AGENT}e"
RequestHeader set INFO_IS_SUBREQ "%{INFO_IS_SUBREQ}e"
RequestHeader set INFO_ORIG_PATH_INFO "%{INFO_ORIG_PATH_INFO}e"
RequestHeader set INFO_ORIG_PATH_TRANSLATED "%{INFO_ORIG_PATH_TRANSLATED}e"
RequestHeader set INFO_ORIG_SCRIPT_FILENAME "%{INFO_ORIG_SCRIPT_FILENAME}e"
RequestHeader set INFO_ORIG_SCRIPT_NAME "%{INFO_ORIG_SCRIPT_NAME}e"
RequestHeader set INFO_PATH "%{INFO_PATH}e"
RequestHeader set INFO_PATH_INFO "%{INFO_PATH_INFO}e"
RequestHeader set INFO_QUERY_STRING "%{INFO_QUERY_STRING}e"
RequestHeader set INFO_REDIRECT_QUERY_STRING "%{INFO_REDIRECT_QUERY_STRING}e"
RequestHeader set INFO_REDIRECT_REMOTE_USER "%{INFO_REDIRECT_REMOTE_USER}e"
RequestHeader set INFO_REDIRECT_STATUS "%{INFO_REDIRECT_STATUS}e"
RequestHeader set INFO_REDIRECT_URL "%{INFO_REDIRECT_URL}e"
RequestHeader set INFO_REMOTE_ADDR "%{INFO_REMOTE_ADDR}e"
RequestHeader set INFO_REMOTE_HOST "%{INFO_REMOTE_HOST}e"
RequestHeader set INFO_REMOTE_IDENT "%{INFO_REMOTE_IDENT}e"
RequestHeader set INFO_REMOTE_PORT "%{INFO_REMOTE_PORT}e"
RequestHeader set INFO_REMOTE_USER "%{INFO_REMOTE_USER}e"
RequestHeader set INFO_REQUEST_FILENAME "%{INFO_REQUEST_FILENAME}e"
RequestHeader set INFO_REQUEST_METHOD "%{INFO_REQUEST_METHOD}e"
RequestHeader set INFO_REQUEST_URI "%{INFO_REQUEST_URI}e"
RequestHeader set INFO_REQUEST_URI "%{INFO_REQUEST_URI}e"
RequestHeader set INFO_SCRIPT_FILENAME "%{INFO_SCRIPT_FILENAME}e"
RequestHeader set INFO_SCRIPT_GROUP "%{INFO_SCRIPT_GROUP}e"
RequestHeader set INFO_SCRIPT_NAME "%{INFO_SCRIPT_NAME}e"
RequestHeader set INFO_SCRIPT_URI "%{INFO_SCRIPT_URI}e"
RequestHeader set INFO_SCRIPT_URL "%{INFO_SCRIPT_URL}e"
RequestHeader set INFO_SCRIPT_USER "%{INFO_SCRIPT_USER}e"
RequestHeader set INFO_SERVER_ADDR "%{INFO_SERVER_ADDR}e"
RequestHeader set INFO_SERVER_ADMIN "%{INFO_SERVER_ADMIN}e"
RequestHeader set INFO_SERVER_NAME "%{INFO_SERVER_NAME}e"
RequestHeader set INFO_SERVER_PORT "%{INFO_SERVER_PORT}e"
RequestHeader set INFO_SERVER_PROTOCOL "%{INFO_SERVER_PROTOCOL}e"
RequestHeader set INFO_SERVER_SIGNATURE "%{INFO_SERVER_SIGNATURE}e"
RequestHeader set INFO_SERVER_SOFTWARE "%{INFO_SERVER_SOFTWARE}e"
RequestHeader set INFO_THE_REQUEST "%{INFO_THE_REQUEST}e"
RequestHeader set INFO_TIME "%{INFO_TIME}e"
RequestHeader set INFO_TIME_DAY "%{INFO_TIME_DAY}e"
RequestHeader set INFO_TIME_HOUR "%{INFO_TIME_HOUR}e"
RequestHeader set INFO_TIME_MIN "%{INFO_TIME_MIN}e"
RequestHeader set INFO_TIME_MON "%{INFO_TIME_MON}e"
RequestHeader set INFO_TIME_SEC "%{INFO_TIME_SEC}e"
RequestHeader set INFO_TIME_WDAY "%{INFO_TIME_WDAY}e"
RequestHeader set INFO_TIME_YEAR "%{INFO_TIME_YEAR}e"
RequestHeader set INFO_TZ "%{INFO_TZ}e"
RequestHeader set INFO_UNIQUE_ID "%{INFO_UNIQUE_ID}e"
&nbsp;
Options +FollowSymLinks +ExecCGI
DirectoryIndex /cgi-bin/rewrite-test/index.php
&nbsp;
Header echo ^.*
&nbsp;
AuthType Digest
AuthName "AskApache Pro"
AuthDigestFile /home/askapache/sites/askapache.com/.htpasswd-pro
AuthDigestDomain / http://www.askapache.com/cgi-bin/rewrite-test/ https://www.askapache.com/cgi-bin/rewrite-test/
Require user askapache
&nbsp;
SetEnv MODSEC_ENABLE=On
&nbsp;
SetEnvIfNoCase ^WWW-Auth "(.+)" HTTP_WWW_AUTHORIZATION=$1
SetEnvIfNoCase ^If "(.+)" HTTP_IF_MODIFIED_SINCE=$1
SetEnvIfNoCase ^If-None-Match$ "(.+)" HTTP_IF_NONE_MATCH=$1
SetEnvIfNoCase ^Cache-Control$ "(.+)" HTTP_CACHE_CONTROL=$1
SetEnvIfNoCase ^Connection$ "(.+)" HTTP_CONNECTION=$1
SetEnvIfNoCase ^Keep-Alive$ "(.+)" HTTP_KEEP_ALIVE=$1
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
SetEnvIfNoCase ^Authorization$ ".+username=\"(.+)\".+" HTTP_REMOTE_USER=$1
SetEnvIfNoCase ^Content-Type$ "(.+)" HTTP_CONTENT_TYPE=$1
SetEnvIfNoCase ^Content-Length$ "(.+)" HTTP_CONTENT_LENGTH=$1
SetEnvIfNoCase Server_Addr "(.+)" SERVER_ADDR=$1
SetEnvIfNoCase Request_Method "(.+)" REQUEST_METHOD=$1
SetEnvIfNoCase Request_Protocol "(.+)" REQUEST_PROTOCOL=$1
SetEnvIfNoCase Request_URI "(.+)" REQUEST_URI=$1
&nbsp;
ErrorDocument 100 /cgi-bin/rewrite-test/index.php?g=100
ErrorDocument 101 /cgi-bin/rewrite-test/index.php?g=101
ErrorDocument 102 /cgi-bin/rewrite-test/index.php?g=102
ErrorDocument 200 /cgi-bin/rewrite-test/index.php?g=200
ErrorDocument 201 /cgi-bin/rewrite-test/index.php?g=201
ErrorDocument 202 /cgi-bin/rewrite-test/index.php?g=202
ErrorDocument 203 /cgi-bin/rewrite-test/index.php?g=203
ErrorDocument 204 /cgi-bin/rewrite-test/index.php?g=204
ErrorDocument 205 /cgi-bin/rewrite-test/index.php?g=205
ErrorDocument 206 /cgi-bin/rewrite-test/index.php?g=206
ErrorDocument 207 /cgi-bin/rewrite-test/index.php?g=207
ErrorDocument 300 /cgi-bin/rewrite-test/index.php?g=300
ErrorDocument 301 /cgi-bin/rewrite-test/index.php?g=301
ErrorDocument 302 /cgi-bin/rewrite-test/index.php?g=302
ErrorDocument 303 /cgi-bin/rewrite-test/index.php?g=303
ErrorDocument 304 /cgi-bin/rewrite-test/index.php?g=304
ErrorDocument 305 /cgi-bin/rewrite-test/index.php?g=305
ErrorDocument 306 /cgi-bin/rewrite-test/index.php?g=306
ErrorDocument 307 /cgi-bin/rewrite-test/index.php?g=307
ErrorDocument 400 /cgi-bin/rewrite-test/index.php?g=400
ErrorDocument 401 /cgi-bin/rewrite-test/index.php?g=401
ErrorDocument 402 /cgi-bin/rewrite-test/index.php?g=402
ErrorDocument 403 /cgi-bin/rewrite-test/index.php?g=403
ErrorDocument 404 /cgi-bin/rewrite-test/index.php?g=404
ErrorDocument 405 /cgi-bin/rewrite-test/index.php?g=405
ErrorDocument 406 /cgi-bin/rewrite-test/index.php?g=406
ErrorDocument 407 /cgi-bin/rewrite-test/index.php?g=407
ErrorDocument 408 /cgi-bin/rewrite-test/index.php?g=408
ErrorDocument 409 /cgi-bin/rewrite-test/index.php?g=409
ErrorDocument 410 /cgi-bin/rewrite-test/index.php?g=410
ErrorDocument 411 /cgi-bin/rewrite-test/index.php?g=411
ErrorDocument 412 /cgi-bin/rewrite-test/index.php?g=412
ErrorDocument 413 /cgi-bin/rewrite-test/index.php?g=413
ErrorDocument 414 /cgi-bin/rewrite-test/index.php?g=414
ErrorDocument 415 /cgi-bin/rewrite-test/index.php?g=415
ErrorDocument 416 /cgi-bin/rewrite-test/index.php?g=416
ErrorDocument 417 /cgi-bin/rewrite-test/index.php?g=417
ErrorDocument 418 /cgi-bin/rewrite-test/index.php?g=418
ErrorDocument 419 /cgi-bin/rewrite-test/index.php?g=419
ErrorDocument 420 /cgi-bin/rewrite-test/index.php?g=420
ErrorDocument 421 /cgi-bin/rewrite-test/index.php?g=421
ErrorDocument 422 /cgi-bin/rewrite-test/index.php?g=422
ErrorDocument 423 /cgi-bin/rewrite-test/index.php?g=423
ErrorDocument 424 /cgi-bin/rewrite-test/index.php?g=424
ErrorDocument 425 /cgi-bin/rewrite-test/index.php?g=425
ErrorDocument 426 /cgi-bin/rewrite-test/index.php?g=426
ErrorDocument 500 /cgi-bin/rewrite-test/index.php?g=500
ErrorDocument 501 /cgi-bin/rewrite-test/index.php?g=501
ErrorDocument 502 /cgi-bin/rewrite-test/index.php?g=502
ErrorDocument 503 /cgi-bin/rewrite-test/index.php?g=503
ErrorDocument 504 /cgi-bin/rewrite-test/index.php?g=504
ErrorDocument 505 /cgi-bin/rewrite-test/index.php?g=505
ErrorDocument 506 /cgi-bin/rewrite-test/index.php?g=506
ErrorDocument 507 /cgi-bin/rewrite-test/index.php?g=507
ErrorDocument 508 /cgi-bin/rewrite-test/index.php?g=508
ErrorDocument 509 /cgi-bin/rewrite-test/index.php?g=509
ErrorDocument 510 /cgi-bin/rewrite-test/index.php?g=510
&nbsp;
RewriteEngine On
RewriteBase /
&nbsp;
RewriteRule .* - [E=IN_AUTH_TYPE:%{AUTH_TYPE}]
RewriteRule .* - [E=IN_CONTENT_LENGTH:%{CONTENT_LENGTH}]
RewriteRule .* - [E=IN_CONTENT_TYPE:%{CONTENT_TYPE}]
RewriteRule .* - [E=IN_DATE_GMT:%{DATE_GMT}]
RewriteRule .* - [E=IN_DATE_LOCAL:%{DATE_LOCAL}]
RewriteRule .* - [E=IN_DOCUMENT_NAME:%{DOCUMENT_NAME}]
RewriteRule .* - [E=IN_DOCUMENT_PATH_INFO:%{DOCUMENT_PATH_INFO}]
RewriteRule .* - [E=IN_DOCUMENT_ROOT:%{DOCUMENT_ROOT}]
RewriteRule .* - [E=IN_DOCUMENT_URI:%{DOCUMENT_URI}]
RewriteRule .* - [E=IN_GATEWAY_INTERFACE:%{GATEWAY_INTERFACE}]
RewriteRule .* - [E=IN_LAST_MODIFIED:%{LAST_MODIFIED}]
RewriteRule .* - [E=IN_PATH_INFO:%{PATH_INFO}]
RewriteRule .* - [E=IN_PATH_TRANSLATED:%{PATH_TRANSLATED}]
RewriteRule .* - [E=IN_QUERY_STRING:%{QUERY_STRING}]
RewriteRule .* - [E=IN_QUERY_STRING_UNESCAPED:%{QUERY_STRING_UNESCAPED}]
RewriteRule .* - [E=IN_REMOTE_ADDR:%{REMOTE_ADDR}]
RewriteRule .* - [E=IN_REMOTE_HOST:%{REMOTE_HOST}]
RewriteRule .* - [E=IN_REMOTE_IDENT:%{REMOTE_IDENT}]
RewriteRule .* - [E=IN_REMOTE_PORT:%{REMOTE_PORT}]
RewriteRule .* - [E=IN_REMOTE_USER:%{REMOTE_USER}]
RewriteRule .* - [E=IN_REDIRECT_HANDLER:%{REDIRECT_HANDLER}]
RewriteRule .* - [E=IN_REDIRECT_QUERY_STRING:%{REDIRECT_QUERY_STRING}]
RewriteRule .* - [E=IN_REDIRECT_REMOTE_USER:%{REDIRECT_REMOTE_USER}]
RewriteRule .* - [E=IN_REDIRECT_STATUS:%{REDIRECT_STATUS}]
RewriteRule .* - [E=IN_REDIRECT_URL:%{REDIRECT_URL}]
RewriteRule .* - [E=IN_REQUEST_METHOD:%{REQUEST_METHOD}]
RewriteRule .* - [E=IN_REQUEST_URI:%{REQUEST_URI}]
RewriteRule .* - [E=IN_SCRIPT_FILENAME:%{SCRIPT_FILENAME}]
RewriteRule .* - [E=IN_SCRIPT_NAME:%{SCRIPT_NAME}]
RewriteRule .* - [E=IN_SERVER_ADMIN:%{SERVER_ADMIN}]
RewriteRule .* - [E=IN_SERVER_NAME:%{SERVER_NAME}]
RewriteRule .* - [E=IN_SERVER_ADDR:%{SERVER_ADDR}]
RewriteRule .* - [E=IN_SERVER_PORT:%{SERVER_PORT}]
RewriteRule .* - [E=IN_SERVER_PROTOCOL:%{SERVER_PROTOCOL}]
RewriteRule .* - [E=IN_SERVER_SIGNATURE:%{SERVER_SIGNATURE}]
RewriteRule .* - [E=IN_SERVER_SOFTWARE:%{SERVER_SOFTWARE}]
RewriteRule .* - [E=IN_USER_NAME:%{USER_NAME}]
RewriteRule .* - [E=IN_TZ:%{TZ}]
RewriteRule .* - [E=IN_API_VERSION:%{API_VERSION}]
RewriteRule .* - [E=IN_HTTPS:%{HTTPS}]
RewriteRule .* - [E=IN_HTTP_ACCEPT:%{HTTP_ACCEPT}]
RewriteRule .* - [E=IN_HTTP_ACCEPT_CHARSET:%{HTTP_ACCEPT_CHARSET}]
RewriteRule .* - [E=IN_HTTP_ACCEPT_ENCODING:%{HTTP_ACCEPT_ENCODING}]
RewriteRule .* - [E=IN_HTTP_ACCEPT_LANGUAGE:%{HTTP_ACCEPT_LANGUAGE}]
RewriteRule .* - [E=IN_HTTP_CACHE_CONTROL:%{HTTP_CACHE_CONTROL}]
RewriteRule .* - [E=IN_HTTP_CONNECTION:%{HTTP_CONNECTION}]
RewriteRule .* - [E=IN_HTTP_COOKIE:%{HTTP_COOKIE}]
RewriteRule .* - [E=IN_HTTP_FORWARDED:%{HTTP_FORWARDED}]
RewriteRule .* - [E=IN_HTTP_HOST:%{HTTP_HOST}]
RewriteRule .* - [E=IN_HTTP_KEEP_ALIVE:%{HTTP_KEEP_ALIVE}]
RewriteRule .* - [E=IN_HTTP_PROXY_CONNECTION:%{HTTP_PROXY_CONNECTION}]
RewriteRule .* - [E=IN_HTTP_REFERER:%{HTTP_REFERER}]
RewriteRule .* - [E=IN_HTTP_USER_AGENT:%{HTTP_USER_AGENT}]
RewriteRule .* - [E=IN_IS_SUBREQ:%{IS_SUBREQ}]
RewriteRule .* - [E=IN_ORIG_PATH_INFO:%{ORIG_PATH_INFO}]
RewriteRule .* - [E=IN_ORIG_PATH_TRANSLATED:%{ORIG_PATH_TRANSLATED}]
RewriteRule .* - [E=IN_ORIG_SCRIPT_FILENAME:%{ORIG_SCRIPT_FILENAME}]
RewriteRule .* - [E=IN_ORIG_SCRIPT_NAME:%{ORIG_SCRIPT_NAME}]
RewriteRule .* - [E=IN_PATH:%{PATH}]
RewriteRule .* - [E=IN_PHP_SELF:%{PHP_SELF}]
RewriteRule .* - [E=IN_REQUEST_FILENAME:%{REQUEST_FILENAME}]
RewriteRule .* - [E=IN_REQUEST_TIME:%{REQUEST_TIME}]
RewriteRule .* - [E=IN_SCRIPT_GROUP:%{SCRIPT_GROUP}]
RewriteRule .* - [E=IN_SCRIPT_USER:%{SCRIPT_USER}]
RewriteRule .* - [E=IN_THE_REQUEST:%{THE_REQUEST}]
RewriteRule .* - [E=IN_TIME:%{TIME}]
RewriteRule .* - [E=IN_TIME_DAY:%{TIME_DAY}]
RewriteRule .* - [E=IN_TIME_HOUR:%{TIME_HOUR}]
RewriteRule .* - [E=IN_TIME_MIN:%{TIME_MIN}]
RewriteRule .* - [E=IN_TIME_MON:%{TIME_MON}]
RewriteRule .* - [E=IN_TIME_SEC:%{TIME_SEC}]
RewriteRule .* - [E=IN_TIME_WDAY:%{TIME_WDAY}]
RewriteRule .* - [E=IN_TIME_YEAR:%{TIME_YEAR}]
RewriteRule .* - [E=IN_PATH:%{PATH}]
RewriteRule .* - [E=IN_SCRIPT_URI:%{SCRIPT_URI}]
RewriteRule .* - [E=IN_SCRIPT_URL:%{SCRIPT_URL}]
RewriteRule .* - [E=IN_UNIQUE_ID:%{UNIQUE_ID}]
&nbsp;
RewriteRule .* - [E=ENV_PATH:%{ENV:PATH}]
RewriteRule .* - [E=ENV_SCRIPT_URI:%{ENV:SCRIPT_URI}]
RewriteRule .* - [E=ENV_SCRIPT_URL:%{ENV:SCRIPT_URL}]
RewriteRule .* - [E=ENV_UNIQUE_ID:%{ENV:UNIQUE_ID}]
&nbsp;
RequestHeader set AUTH_TYPE "%{IN_AUTH_TYPE}e"
RequestHeader set CONTENT_LENGTH "%{IN_CONTENT_LENGTH}e"
RequestHeader set CONTENT_TYPE "%{IN_CONTENT_TYPE}e"
RequestHeader set DATE_GMT "%{IN_DATE_GMT}e"
RequestHeader set DATE_LOCAL "%{IN_DATE_LOCAL}e"
RequestHeader set DOCUMENT_NAME "%{IN_DOCUMENT_NAME}e"
RequestHeader set DOCUMENT_PATH_INFO "%{IN_DOCUMENT_PATH_INFO}e"
RequestHeader set DOCUMENT_ROOT "%{IN_DOCUMENT_ROOT}e"
RequestHeader set DOCUMENT_URI "%{IN_DOCUMENT_URI}e"
RequestHeader set GATEWAY_INTERFACE "%{IN_GATEWAY_INTERFACE}e"
RequestHeader set LAST_MODIFIED "%{IN_LAST_MODIFIED}e"
RequestHeader set PATH_INFO "%{IN_PATH_INFO}e"
RequestHeader set PATH_TRANSLATED "%{IN_PATH_TRANSLATED}e"
RequestHeader set QUERY_STRING "%{IN_QUERY_STRING}e"
RequestHeader set QUERY_STRING_UNESCAPED "%{IN_QUERY_STRING_UNESCAPED}e"
RequestHeader set REMOTE_ADDR "%{IN_REMOTE_ADDR}e"
RequestHeader set REMOTE_HOST "%{IN_REMOTE_HOST}e"
RequestHeader set REMOTE_IDENT "%{IN_REMOTE_IDENT}e"
RequestHeader set REMOTE_PORT "%{IN_REMOTE_PORT}e"
RequestHeader set REMOTE_USER "%{IN_REMOTE_USER}e"
RequestHeader set REDIRECT_HANDLER "%{IN_REDIRECT_HANDLER}e"
RequestHeader set REDIRECT_QUERY_STRING "%{IN_REDIRECT_QUERY_STRING}e"
RequestHeader set REDIRECT_REMOTE_USER "%{IN_REDIRECT_REMOTE_USER}e"
RequestHeader set REDIRECT_STATUS "%{IN_REDIRECT_STATUS}e"
RequestHeader set REDIRECT_URL "%{IN_REDIRECT_URL}e"
RequestHeader set REQUEST_METHOD "%{IN_REQUEST_METHOD}e"
RequestHeader set REQUEST_URI "%{IN_REQUEST_URI}e"
RequestHeader set SCRIPT_FILENAME "%{IN_SCRIPT_FILENAME}e"
RequestHeader set SCRIPT_NAME "%{IN_SCRIPT_NAME}e"
RequestHeader set SCRIPT_URI "%{IN_SCRIPT_URI}e"
RequestHeader set SCRIPT_URL "%{IN_SCRIPT_URL}e"
RequestHeader set SERVER_ADMIN "%{IN_SERVER_ADMIN}e"
RequestHeader set SERVER_NAME "%{IN_SERVER_NAME}e"
RequestHeader set SERVER_ADDR "%{IN_SERVER_ADDR}e"
RequestHeader set SERVER_PORT "%{IN_SERVER_PORT}e"
RequestHeader set SERVER_PROTOCOL "%{IN_SERVER_PROTOCOL}e"
RequestHeader set SERVER_SIGNATURE "%{IN_SERVER_SIGNATURE}e"
RequestHeader set SERVER_SOFTWARE "%{IN_SERVER_SOFTWARE}e"
RequestHeader set UNIQUE_ID "%{IN_UNIQUE_ID}e"
RequestHeader set USER_NAME "%{IN_USER_NAME}e"
RequestHeader set TZ "%{IN_TZ}e"
RequestHeader set API_VERSION "%{IN_API_VERSION}e"
RequestHeader set HTTPS "%{IN_HTTPS}e"
RequestHeader set HTTP_ACCEPT "%{IN_HTTP_ACCEPT}e"
RequestHeader set HTTP_ACCEPT_CHARSET "%{IN_HTTP_ACCEPT_CHARSET}e"
RequestHeader set HTTP_ACCEPT_ENCODING "%{IN_HTTP_ACCEPT_ENCODING}e"
RequestHeader set HTTP_ACCEPT_LANGUAGE "%{IN_HTTP_ACCEPT_LANGUAGE}e"
RequestHeader set HTTP_CACHE_CONTROL "%{IN_HTTP_CACHE_CONTROL}e"
RequestHeader set HTTP_CONNECTION "%{IN_HTTP_CONNECTION}e"
RequestHeader set HTTP_COOKIE "%{IN_HTTP_COOKIE}e"
RequestHeader set HTTP_FORWARDED "%{IN_HTTP_FORWARDED}e"
RequestHeader set HTTP_HOST "%{IN_HTTP_HOST}e"
RequestHeader set HTTP_KEEP_ALIVE "%{IN_HTTP_KEEP_ALIVE}e"
RequestHeader set HTTP_PROXY_CONNECTION "%{IN_HTTP_PROXY_CONNECTION}e"
RequestHeader set HTTP_REFERER "%{IN_HTTP_REFERER}e"
RequestHeader set HTTP_USER_AGENT "%{IN_HTTP_USER_AGENT}e"
RequestHeader set IS_SUBREQ "%{IN_IS_SUBREQ}e"
RequestHeader set ORIG_PATH_INFO "%{IN_ORIG_PATH_INFO}e"
RequestHeader set ORIG_PATH_TRANSLATED "%{IN_ORIG_PATH_TRANSLATED}e"
RequestHeader set ORIG_SCRIPT_FILENAME "%{IN_ORIG_SCRIPT_FILENAME}e"
RequestHeader set ORIG_SCRIPT_NAME "%{IN_ORIG_SCRIPT_NAME}e"
RequestHeader set PATH "%{IN_PATH}e"
RequestHeader set PHP_SELF "%{IN_PHP_SELF}e"
RequestHeader set REQUEST_FILENAME "%{IN_REQUEST_FILENAME}e"
RequestHeader set REQUEST_TIME "%{IN_REQUEST_TIME}e"
RequestHeader set SCRIPT_GROUP "%{IN_SCRIPT_GROUP}e"
RequestHeader set SCRIPT_USER "%{IN_SCRIPT_USER}e"
RequestHeader set THE_REQUEST "%{IN_THE_REQUEST}e"
RequestHeader set TIME "%{IN_TIME}e"
RequestHeader set TIME_DAY "%{IN_TIME_DAY}e"
RequestHeader set TIME_HOUR "%{IN_TIME_HOUR}e"
RequestHeader set TIME_MIN "%{IN_TIME_MIN}e"
RequestHeader set TIME_MON "%{IN_TIME_MON}e"
RequestHeader set TIME_SEC "%{IN_TIME_SEC}e"
RequestHeader set TIME_WDAY "%{IN_TIME_WDAY}e"
RequestHeader set TIME_YEAR "%{IN_TIME_YEAR}e"
&nbsp;
SetEnvIfNoCase ^WWW-Auth "(.+)" HTTP_WWW_AUTHORIZATION=$1
SetEnvIfNoCase ^If "(.+)" HTTP_IF_MODIFIED_SINCE=$1
SetEnvIfNoCase ^If-None-Match$ "(.+)" HTTP_IF_NONE_MATCH=$1
SetEnvIfNoCase ^Cache-Control$ "(.+)" HTTP_CACHE_CONTROL=$1
SetEnvIfNoCase ^Connection$ "(.+)" HTTP_CONNECTION=$1
SetEnvIfNoCase ^Keep-Alive$ "(.+)" HTTP_KEEP_ALIVE=$1
SetEnvIfNoCase ^Authorization$ "(.+)" HTTP_AUTHORIZATION=$1
SetEnvIfNoCase ^Content-Type$ "(.+)" HTTP_CONTENT_TYPE=$1
SetEnvIfNoCase ^Content-Length$ "(.+)" HTTP_CONTENT_LENGTH=$1
SetEnvIfNoCase ^Authorization$ ".+username=\"([a-zA-Z0-9]+)\".+" REMOTE_USER=$1
SetEnvIfNoCase Server_Addr "(.+)" SERVER_ADDR=$1
SetEnvIfNoCase Request_Method "(.+)" REQUEST_METHOD=$1
SetEnvIfNoCase Request_Protocol "(.+)" REQUEST_PROTOCOL=$1
SetEnvIfNoCase Request_URI "(.+)" REQUEST_URI=$1
&nbsp;
RequestHeader set IF_MODIFIED_SINCE "%{HTTP_IF_MODIFIED_SINCE}e"
RequestHeader set IF_NONE_MATCH "%{HTTP_IF_NONE_MATCH}e"
RequestHeader set CACHE_CONTROL "%{HTTP_CACHE_CONTROL}e"
RequestHeader set CONNECTION "%{HTTP_CONNECTION}e"
RequestHeader set KEEP_ALIVE "%{HTTP_KEEP_ALIVE}e"
RequestHeader set AUTHORIZATION "%{HTTP_AUTHORIZATION}e"
RequestHeader set REMOTE_USER "%{REMOTE_USER}e"
RequestHeader set CONTENT_TYPE "%{HTTP_CONTENT_TYPE}e"
RequestHeader set CONTENT_LENGTH "%{HTTP_CONTENT_LENGTH}e"
RequestHeader set SERVER_ADDR "%{SERVER_ADDR}e"
RequestHeader set REQUEST_METHOD "%{REQUEST_METHOD}e"
RequestHeader set REQUEST_PROTOCOL "%{REQUEST_PROTOCOL}e"
RequestHeader set REQUEST_URI "%{REQUEST_URI}e"
&nbsp;
RequestHeader set UNIQUE_ID "%{ENV_UNIQUE_ID}e"
RequestHeader set SCRIPT_URL "%{ENV_SCRIPT_URL}e"
RequestHeader set SCRIPT_URI "%{ENV_SCRIPT_URI}e"
RequestHeader set PATH "%{ENV_PATH}e"
&nbsp;
Options +ExecCGI +FollowSymLinks
&nbsp;
Order Deny,Allow
Deny from All
Allow from 208.113.134.190  64.111.114.111 208.113.134.203 208.113.152.201 env=REDIRECT_STATUS
Satisfy Any
&nbsp;
SecFilterEngine Off</pre>



<h2>More Mod_Security (1)</h2>
<pre>#
# Order Deny,Allow
# First, all Allow directives are evaluated; at least one must match, or the request is rejected.
# Next, all Deny directives are evaluated. If any matches, the request is rejected.
# Last, any requests which do not match an Allow or a Deny directive are denied by default.
#
Order Allow,Deny
Allow from all
Deny from 217.219.
&nbsp;
#Order Deny,Allow
# First, all Deny directives are evaluated; if any match, the request is denied unless it also matches an Allow directive.
# Any requests which do not match any Allow or Deny directives are permitted.
&nbsp;
#SetEnvIf content-type (multipart/form-data)(.*) NEW_CONTENT_TYPE=application/x-www-form-urlencoded$2 OLD_CONTENT_TYPE=$1$2
#RequestHeader set content-type %{NEW_CONTENT_TYPE}e env=NEW_CONTENT_TYPE
SetEnvIfNoCase Content-Type "^multipart/form-data" !MODSEC_NOPOSTBUFFERING
SetEnvIfNoCase Content-Type "^application/x-www-form-urlencoded" !MODSEC_NOPOSTBUFFERING
SetEnv suppress-error-charset
SetEnvIfNoCase Content-Type "^multipart/form-data" !MODSEC_NOPOSTBUFFERING
&nbsp;
SetEnvIf Request_URI "^/(cgi-bin/search\.php|cgi-bin/java\.cgi|wp-admin/.*)" MODSEC_ENABLE=Off
SetEnvIf Request_URI "^/(online-tools/js-compress.*)" "MODSEC_NOPOSTBUFFERING=Do not buffer file uploads"
SetEnvIfNoCase Remote_Addr ^208\.113\.134\.190$ MODSEC_ENABLE=Off
SetEnvIfNoCase Remote_Addr ^64\.111\.114\.111$ MODSEC_ENABLE=Off
&nbsp;
### Section 1: Global Environment
#
# The directives in this section affect the overall operation of Apache,
# such as the number of concurrent requests it can handle or where it
# can find its configuration files.
#
#
# TZ: Your address, where problems with the server should be
# e-mailed.  This address appears on some server-generated pages, such
# as error documents.  e.g. admin@your-domain.com
#
SetEnv TZ America/Indianapolis
&nbsp;
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed.  This address appears on some server-generated pages, such
# as error documents.  e.g. admin@your-domain.com
#
SetEnv SERVER_ADMIN webmaster@askapache.com
&nbsp;
#
# Optionally add a line containing the server version and virtual host
# name to server-generated pages (internal error documents, FTP directory
# listings, mod_status and mod_info output etc., but not CGI generated
# documents or custom error documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of:  On | Off | EMail
#
ServerSignature Off
&nbsp;
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
#   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# The Options directive is both complicated and important.  Please see
# http://httpd.apache.org/docs/2.0/mod/core.html#options
# for more information.
#
Options -Indexes -Includes -ExecCGI -MultiViews
&nbsp;
#
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
DirectoryIndex index.php
&nbsp;
#
# Action lets you define media types that will execute a script whenever
# a matching file is called. This eliminates the need for repeated URL
# pathnames for oft-used CGI file processors.
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
Action php5-cgi /bin/php.cgi
&nbsp;
#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
AddHandler php5-cgi .php .inc
&nbsp;
#
# Commonly used filename extensions to character sets. You probably
# want to avoid clashes with the language extensions, unless you
# are good at carefully testing your setup after each change.
# See http://www.iana.org/assignments/character-sets for the
# official list of charset names and their respective RFCs.
#
AddDefaultCharset UTF-8
&nbsp;
#
# AddType allows you to add to or override the MIME configuration
# file mime.types for specific file types.
#
#
AddType &#039;application/rdf+xml; charset=UTF-8&#039; .rdf
AddType &#039;application/xhtml+xml; charset=UTF-8&#039; .xhtml
AddType &#039;application/xhtml+xml; charset=UTF-8&#039; .xhtml.gz
AddType &#039;text/html; charset=UTF-8&#039; .html
AddType &#039;text/html; charset=UTF-8&#039; .html.gz
AddType application/octet-stream .rar .chm .bz2 .tgz .msi .pdf .exe
AddType application/vnd.ms-excel .csv
AddType application/x-httpd-php-source .phps
AddType application/x-pilot .prc .pdb
AddType application/x-shockwave-flash .swf
AddType application/xrds+xml .xrdf
AddType text/plain .ini .sh .bsh .bash .awk .nawk .gawk .csh .var .c .in .h .asc .md5 .sha .sha1
AddType video/x-flv .flv
&nbsp;
#
# AddEncoding allows you to have certain browsers uncompress
# information on the fly. Note: Not all browsers support this.
# Despite the name similarity, the following Add* directives have nothing
# to do with the FancyIndexing customization directives above.
#
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
&nbsp;
#
# DefaultType: the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value.  If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/html</pre>




<h2>Error Documents</h2>
<pre>#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
#100 Continue
#101 Switching Protocols
#102 Processing
#200 OK
#201 Created
#202 Accepted
#203 Non-Authoritative Information
#204 No Content
#205 Reset Content
#206 Partial Content
#207 Multi-Status
#300 Multiple Choices
#301 Moved Permanently
#302 Found
#303 See Other
#304 Not Modified
#305 Use Proxy
#306 unused
#307 Temporary Redirect
#400 Bad Request
#401 Authorization Required
#402 Payment Required
#403 Forbidden
#404 Not Found
#405 Method Not Allowed
#406 Not Acceptable
#407 Proxy Authentication Required
#408 Request Time-out
#409 Conflict
#410 Gone
#411 Length Required
#412 Precondition Failed
#413 Request Entity Too Large
#414 Request-URI Too Large
#415 Unsupported Media Type
#416 Requested Range Not Satisfiable
#417 Expectation Failed
#418 unused
#419 unused
#420 unused
#421 unused
#422 Unprocessable Entity
#423 Locked
#424 Failed Dependency
#425 No code
#426 Upgrade Required
#500 Internal Server Error
#501 Method Not Implemented
#502 Bad Gateway
#503 Service Temporarily Unavailable
#504 Gateway Time-out
#505 HTTP Version Not Supported
#506 Variant Also Negotiates
#507 Insufficient Storage
#508 unused
#509 unused
#510 Not Extended
&nbsp;
#ErrorDocument 100 /e/100_CONTINUE.html
#ErrorDocument 101 /e/101_SWITCHING_PROTOCOLS.html
#ErrorDocument 102 /e/102_PROCESSING.html
&nbsp;
#ErrorDocument 200 /e/200_OK.html
#ErrorDocument 201 /e/201_CREATED.html
#ErrorDocument 202 /e/202_ACCEPTED.html
#ErrorDocument 203 /e/203_NON_AUTHORITATIVE.html
#ErrorDocument 204 /e/204_NO_CONTENT.html
#ErrorDocument 205 /e/205_RESET_CONTENT.html
#ErrorDocument 206 /e/206_PARTIAL_CONTENT.html
#ErrorDocument 207 /e/207_MULTI_STATUS.html
&nbsp;
#ErrorDocument 300 /e/300_MULTIPLE_CHOICES.html
#ErrorDocument 301 /e/301_MOVED_PERMANENTLY.html
#ErrorDocument 302 /e/302_MOVED_TEMPORARILY.html
#ErrorDocument 303 /e/303_SEE_OTHER.html
#ErrorDocument 304 /e/304_NOT_MODIFIED.html
#ErrorDocument 305 /e/305_USE_PROXY.html
#ErrorDocument 307 /e/307_TEMPORARY_REDIRECT.html
&nbsp;
ErrorDocument 400 /e/400_BAD_REQUEST.html
ErrorDocument 401 /e/401_UNAUTHORIZED.html
ErrorDocument 402 /e/402_PAYMENT_REQUIRED.html
ErrorDocument 403 /e/403_FORBIDDEN.html
#ErrorDocument 404 /e/404_NOT_FOUND.html
ErrorDocument 404 /index.php?error=404
ErrorDocument 405 /e/405_METHOD_NOT_ALLOWED.html
ErrorDocument 406 /e/406_NOT_ACCEPTABLE.html
ErrorDocument 407 /e/407_PROXY_AUTHENTICATION_REQUIRED.html
ErrorDocument 408 /e/408_REQUEST_TIME_OUT.html
ErrorDocument 409 /e/409_CONFLICT.html
ErrorDocument 410 /e/410_GONE.html
ErrorDocument 411 /e/411_LENGTH_REQUIRED.html
ErrorDocument 412 /e/412_PRECONDITION_FAILED.html
ErrorDocument 413 /e/413_REQUEST_ENTITY_TOO_LARGE.html
ErrorDocument 414 /e/414_REQUEST_URI_TOO_LARGE.html
ErrorDocument 415 /e/415_UNSUPPORTED_MEDIA_TYPE.html
ErrorDocument 416 /e/416_RANGE_NOT_SATISFIABLE.html
ErrorDocument 417 /e/417_EXPECTATION_FAILED.html
ErrorDocument 422 /e/422_UNPROCESSABLE_ENTITY.html
ErrorDocument 423 /e/423_LOCKED.html
ErrorDocument 424 /e/424_FAILED_DEPENDENCY.html
ErrorDocument 426 /e/426_UPGRADE_REQUIRED.html
ErrorDocument 500 /e/500_INTERNAL_SERVER_ERROR.html
ErrorDocument 501 /e/501_NOT_IMPLEMENTED.html
ErrorDocument 502 /e/502_BAD_GATEWAY.html
ErrorDocument 503 /e/503_SERVICE_UNAVAILABLE.html
ErrorDocument 504 /e/504_GATEWAY_TIME_OUT.html
ErrorDocument 505 /e/505_VERSION_NOT_SUPPORTED.html
ErrorDocument 506 /e/506_VARIANT_ALSO_VARIES.html
ErrorDocument 507 /e/507_INSUFFICIENT_STORAGE.html
ErrorDocument 510 /e/510_NOT_EXTENDED.html</pre>



<h2>Caching</h2>
<pre>#
#  HEADERS and CACHING
#
Header unset Pragma
FileETag None
Header unset ETag
&nbsp;
# 1 YEAR
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)$"&gt;
Header unset P3P
Header unset Pragma
FileETag None
Header unset ETag
Header set Cache-Control "public,max-age=29030400"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
Header unset Last-Modified
&lt;/filesMatch&gt;
&nbsp;
# 2 HOURS
&lt;filesMatch "\.(html|htm|xml|txt|xsl|rdf|rss)$"&gt;
&lt;ifModule mod_expires.c&gt;
ExpiresActive On
ExpiresDefault A3600
&lt;/ifModule&gt;
&lt;/filesMatch&gt;</pre>



<h2>Redirect Hack</h2>
<pre>#Redirect 400 /e/400
#Redirect 401 /e/401
#Redirect 402 /e/402
#Redirect 403 /e/403
Redirect 404 /index.php?error=404
#Redirect 405 /e/405
#Redirect 406 /e/406
#Redirect 407 /e/407
#Redirect 408 /e/408
#Redirect 409 /e/409
#Redirect 410 /e/410
#Redirect 411 /e/411
#Redirect 412 /e/412
#Redirect 413 /e/413
#Redirect 414 /e/414
#Redirect 415 /e/415
#Redirect 416 /e/416
#Redirect 417 /e/417
#Redirect 418 /e/418
#Redirect 419 /e/419
#Redirect 420 /e/420
#Redirect 421 /e/421
#Redirect 422 /e/422
#Redirect 423 /e/423
#Redirect 424 /e/424
#Redirect 425 /e/425
#Redirect 426 /e/426
#Redirect 500 /e/500
#Redirect 501 /e/501
#Redirect 502 /e/502
#Redirect 503 /e/503
#Redirect 504 /e/504
#Redirect 505 /e/505
#Redirect 506 /e/506
#Redirect 507 /e/507
#Redirect 508 /e/508
#Redirect 509 /e/509
#Redirect 510 /e/510</pre>

<h2>301 PERMANENT REDIRECTS</h2>
<pre>#
# Redirect allows you to tell clients about documents which used to exist in
# your server&#039;s namespace, but do not anymore. This allows you to tell the
# clients where to look for the relocated document.
#
Redirect 301 /12-lessons-for-those-afraid-of-css.html http://www.askapache.com/css/12-lessons-for-those-afraid-of-css.html
Redirect 301 /2006/htaccess/htaccesselite-ultimate-htaccess-article.html http://www.askapache.com/htaccess/apache-htaccess.html
Redirect 301 /2007/phpbb/sending-post-form-data-with-php-curl.html http://www.askapache.com/htaccess/sending-post-form-data-with-php-curl.html
Redirect 301 /2007/webmaster/custom-phpini-with-fastcgi-on-dreamhost.html http://www.askapache.com/dreamhost/custom-phpini-with-fastcgi-on-dreamhost.html
Redirect 301 /2007/webmaster/custom-phpini-with-fastcgi-on-dreamhost.html http://www.askapache.com/dreamhost/custom-phpini-with-fastcgi-on-dreamhost.html
Redirect 301 /2007/webmaster/php-and-ajax-shell-console.html http://www.askapache.com/tools/php-and-ajax-shell-console.html
Redirect 301 /27-request-methods-for-use-with-apache-and-rewritecond-and-htaccess.html http://www.askapache.com/htaccess/27-request-methods-for-use-with-apache-and-rewritecond-and-htaccess.html
Redirect 301 /404-google-wordpress-plugin.html http://www.askapache.com/seo/404-google-wordpress-plugin.html
Redirect 301 /503-service-temporarily-unavailable.html http://www.askapache.com/htaccess/503-service-temporarily-unavailable.html
Redirect 301 /Overview-about.rdf http://www.askapache.com/askapache-home.rdf
Redirect 301 /abbr-acronym.html http://www.askapache.com/xhtml/abbr-acronym.html
Redirect 301 /adsense-robots.html http://www.askapache.com/google/adsense-robots.html
Redirect 301 /alexa-toolbar-firefox.html http://www.askapache.com/tools/alexa-toolbar-firefox.html
Redirect 301 /allowing-access-from-1-static-ip-and-deny-the-rest.html http://www.askapache.com/htaccess/apache-htaccess.html
Redirect 301 /anti-virus-spyware-rootkit.html http://www.askapache.com/security/anti-virus-spyware-rootkit.html
Redirect 301 /apache-ssl-in-htaccess-examples.html http://www.askapache.com/htaccess/apache-ssl-in-htaccess-examples.html
Redirect 301 /awk-tutorial.html http://www.askapache.com/awk/awk-tutorial.html
Redirect 301 /best-adsense-optimization.html http://www.askapache.com/wordpress/best-adsense-optimization.html
Redirect 301 /commonly-used-htaccess-code-examples.html http://www.askapache.com/htaccess/commonly-used-htaccess-code-examples.html
Redirect 301 /css-background-image-sprite.html http://www.askapache.com/css/css-background-image-sprite.html
Redirect 301 /css-browser-screenshots.html http://www.askapache.com/tools/css-browser-screenshots.html
Redirect 301 /css-class-example.html http://www.askapache.com/css/css-class-example.html
Redirect 301 /curl-multi-downloads.html http://www.askapache.com/php/curl-multi-downloads.html
Redirect 301 /custom-boot-menu-in-windows-xp.html http://www.askapache.com/windows/custom-boot-menu-in-windows-xp.html
Redirect 301 /donate http://www.dreamhost.com/donate.cgi?id=8261
Redirect 301 /donate/ http://www.dreamhost.com/donate.cgi?id=8261
Redirect 301 /htaccess.txt http://z.askapache.com/p/htaccess.txt
Redirect 301 /htaccess/404-errorpages.html http://www.askapache.com/seo/google-ajax-search-seo-tips.html
Redirect 301 /htaccess/feedsmith http://www.askapache.com/htaccess/feedsmith-htaccess.html
Redirect 301 /htaccess/http-status-codes.html http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html
Redirect 301 /htaccess/instruct-search-engines-to-come-back-to-site-after-you-finish-working-on-it.html http://www.askapache.com/htaccess/503-service-temporarily-unavailable.html
Redirect 301 /htaccess/speed-up-the-apache-web-server-with-configuration-hacks.html http://www.askapache.com/htaccess/apache-web-server-speed-configuration-hacks.html
Redirect 301 /instruct-search-engines-to-come-back-to-site-after-you-finish-working-on-it.html http://www.askapache.com/htaccess/503-service-temporarily-unavailable.html
Redirect 301 /security/bypassing-vlan.html http://www.askapache.com/security/hacking-vlan-switched-networks.html
Redirect 301 /security/bypassing-vlanbypassing-vlan.html http://www.askapache.com/security/hacking-vlan-switched-networks.html
Redirect 301 /security/rigging-the-dreamhost-site-of-the-month-contest.html http://www.askapache.com/dreamhost/rigging-the-dreamhost-site-of-the-month-contest.html
Redirect 301 /seo/tailrankcom-robot.html http://www.askapache.com/seo/tailrank-robot.html
Redirect 301 /webmaster/caching-tutorial-for-webmasters.html http://www.askapache.com/htaccess/caching-tutorial-for-webmasters.html
Redirect 301 /webmaster/lft-traceroute-tool.html http://www.askapache.com/tools/lft-traceroute-tool.html</pre>



<h2>301 PERMANENT REDIRECTMATCH</h2>
<pre>#
#  PERMANENT REDIRECTMATCH
#
#RedirectMatch 301 ^/&amp;(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/(.+)\.html/$ http://www.askapache.com/$1.html
RedirectMatch 301 ^/&amp;amp(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/.*feed\.gif$ http://z.askapache.com/feed.gif
RedirectMatch 301 ^/([^/]+)//$ http://www.askapache.com/$1/
RedirectMatch 301 ^/(.+)/htaccesselite-ultimate-htaccess-article.html(.*) http://www.askapache.com/htaccess/apache-htaccess.html
RedirectMatch 301 ^/(.+)\.html/([a-z][a-z])/$ http://www.askapache.com/$1.html
RedirectMatch 301 ^/([\(]+)(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/([^9]*)9O1X.3y(.*)/(.*)$ http://www.askapache.com/$2
RedirectMatch 301 ^/.3y(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/200([0-9])/([0-9])(.*)$ http://www.askapache.com/top-100/
RedirectMatch 301 ^/200([0-9])/([^01])(.*)$ http://www.askapache.com/$2$3
RedirectMatch 301 ^/about/glossary(.*)$ http://www.askapache.com/glossary$1
RedirectMatch 301 ^/apache-speed(.*)$ http://www.askapache.com/htaccess/apache-speed$1
RedirectMatch 301 ^/category/(.+)$ http://www.askapache.com/$1
RedirectMatch 301 ^/docs/(.*)$ http://askapache.info/$1
RedirectMatch 301 ^/htaccess/feedsmith-htaccess(.*) http://www.askapache.com/htaccess/redirecting-wordpress-feeds-to-feedburner.html
RedirectMatch 301 ^/robots-txt(.*)$ http://www.askapache.com/robots.txt
RedirectMatch 301 ^/hosting/?$ http://www.askapache.com/hosting/
RedirectMatch 301 ^/.+favicon.ico$ http://www.askapache.com/favicon.ico
#RedirectMatch 301 ^/wp-content/uploads/(.*)$ http://z.askapache.com/uploads/$1
#RedirectMatch 301 ^/z/(.+)$ http://z.askapache.com/$1
#RedirectMatch 301 ^/(z|t|i|j|c|p)/(.*)$ http://z.askapache.com/$1/$2
&nbsp;
#
#  TEMPORARY REDIRECTMATCH
#
RedirectMatch 307 ^/getflash/?$ http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash
RedirectMatch 307 ^/dream/?$ http://www.askapache.com/dreamhost/
RedirectMatch 307 ^/(cse|apachecse|apachecsetest|apachesearch)/?$ http://www.google.com/coop/cse?cx=002660089121042511758%3Akk7rwc2gx0i
RedirectMatch 307 ^/search/lr-lang(.*)$ http://feeds.askapache.com/apache/htaccess
&nbsp;
#
#  PERMANENT GONE
#
RedirectMatch 410 ^/funny(.*)</pre>






<h2>My Favorite modsec_v1 stuff</h2>
<pre># Pass: Allows request to continue, further filters could still halt request.
# Allow: Allows matching requests through, will not be tested against other filters.
# Deny: Stops the request outright, returns a HTTP 500 error code by default.
# Status: Used to specify an alternate HTTP error code.
# Redirect: Matching requests are redirected to the provided URL.
# Exec: Allows execution of a local system binary or script.
# Log: Logs request only.
# Nolog: Does not log request.
# Chain: Allows you to create list of filters for more granulated security. All filters must be cleared before action is taken with the final filter.
&nbsp;
SecFilterEngine On
SecFilterCheckURLEncoding On
SecFilterCheckUnicodeEncoding Off
SecFilterScanPOST On
&nbsp;
#SecUploadKeepFiles On
#SecUploadDir /home/askapache/sites/askapache.com/logs/sec-upload
#SecUploadApproveScript /home/askapache/sites/askapache.com/htdocs/cgi-bin/check.sh
&nbsp;
#SecRuleEngine On
#SecAuditEngine On
#SecAuditEngine Off
SecAuditEngine RelevantOnly
SecAuditLog /home/askapache/sites/askapache.com/logs/modsec_audit.log
SecFilterDebugLog /home/askapache/sites/askapache.com/logs/modsec_debug.log
SecFilterDebugLevel 1
#SecAuditLogRelevantStatus "^(?:1|2(?!00)|5|4(?!04))"
SecAuditLogRelevantStatus "^(1|2(?!00)|4([0-9](0|1|2|5|6|7|8|9))|5)"
SecFilterForceByteRange 1 255
&nbsp;
#SecFilterInheritance Off
# 0 EMERGENCY - system is unusable
# 1 ALERT - action must be taken immediately
# 2 CRITICAL - critical conditions
# 3 ERROR - error conditions
# 4 WARNING - warning conditions
# 5 NOTICE - normal but significant conditions
# 6 INFO - informational
# 7 DEBUG - debug-level messages
&nbsp;
SecFilterDefaultAction "deny,severity:6,status:403"
&nbsp;
#SecFilterSelective REQUEST_METHOD "POST" "pass,auditlog,severity:6"
SecFilterSelective REQUEST_URI "^/(xmlrpc|wp-comments-post)\.php" "pass,log,auditlog,severity:6"
#SecFilterSelective REMOTE_ADDR ^$ "pass,log,auditlog,severity:6"
#SecFilterSelective REMOTE_ADDR ^203\.221\.91\.20$ "pass,log,auditlog,severity:6"
&nbsp;
#SecFilterSelective REQUEST_URI "^/htaccess.*" "pass,log,auditlog"
#SecFilterSelective REQUEST_URI "^/feed.*" "pass,log,auditlog"
#SecFilterSelective REQUEST_URI "^/.*trackback.*" "pass,log,auditlog"
#SecFilterSelective REQUEST_URI "^/valid.*" "pass,log,auditlog"
&nbsp;
#Enforce proper HTTP requests
SecFilterSelective SERVER_PROTOCOL "!^HTTP/(0\.9|1\.0|1\.1)$" "id:340000,rev:1,severity:6,msg:&#039;Bad HTTP Protocol&#039;"
&nbsp;
# Only accept request encodings we know how to handle
SecFilterSelective REQUEST_METHOD "!^(GET|HEAD|POST)$" "chain,id:340001,rev:1,severity:6,msg:&#039;Restricted HTTP function,status:405&#039;"
SecFilterSelective HTTP_Content-Type "!(^$|^application/x-www-form-urlencoded$|^multipart/form-data)"
&nbsp;
# Require Content-Length to be provided with every POST request
SecFilterSelective REQUEST_METHOD "^POST$" "chain,id:340003,rev:1,severity:6,msg:&#039;Content Length not provided with POST&#039;,status:411"
SecFilterSelective HTTP_Content-Length "^$"
&nbsp;
# Don&#039;t accept transfer encodings we know we don&#039;t handle
# (and you don&#039;t need it anyway)
SecFilterSelective HTTP_Transfer-Encoding "!^$" "id:340004,rev:1,severity:6,msg:&#039;Dis-allowed Transfer Encoding&#039;"
&nbsp;
#Generic rule for allowed characters, adjust for your site before activating
##SecFilterSelective REQUEST_URI "!^[a-zA-Z0-9\.\+\_\/\-\?\=\&amp;\%\#]+$" "chain,id:390002,rev:1,severity:4,msg:&#039;Restricted HTTP character set&#039;"
##SecFilterSelective REQUEST_URI "!^/(openid|wp-admin|wp-includes|wp-content|wp-login.php)"
&nbsp;
#HTTP response splitting generic sigs
#SecFilter "Content-Length\:.*Content-Type\:.*Content-Type\:" "id:340005,rev:1,severity:4,msg:&#039;HTTP response splitting&#039;"
&nbsp;
#HTTP response splitting generic sigs
#SecFilter "Content-Length\:" "chain,id:340006,rev:1,severity:4,msg:&#039;HTTP response splitting&#039;"
#SecFilter "Content-Type\:"
&nbsp;
#catch smuggling attacks
#SecFilter "^(GET|POST).*Host:.*^(GET|POST)"  "id:300012,rev:1,severity:4,msg:&#039;catch smuggling attacks&#039;"
&nbsp;
#XSS insertion into Content-Type
#SecFilterSelective THE_REQUEST "Content-Type\:.*(&lt;[[:space:]]*(script|about|applet|activex|chrome)*&gt;.*(script|about|applet|activex|chrome)[[:space:]]*&gt;|onmouseover=|javascript\:)" "id:300002,rev:1,severity:4,msg:&#039;XSS attack in Content-type header&#039;"
&nbsp;
#Code injection via content length
#SecFilterSelective HTTP_Content-Length|HTTP_USER_AGENT "\;(system|passthru|exec)\(" "id:330003,rev:1,severity:4,msg:&#039;Code Injection in Content-Length header&#039;"
&nbsp;
#Don&#039;t accept chunked encodings modsecurity can not look at these, so this is a hole that can bypass your rules, the rule before this one should cover this, but hey paranoia is cheap
#SecFilterSelective HTTP_Transfer-Encoding "chunked" "id:300003,rev:1,severity:4,msg:&#039;Chunked Transfer Encoding denied&#039;"
&nbsp;
##generic recursion signatures
#SecFilterSelective REQUEST_URI "\.\./\.\./" "id:300004,rev:2,severity:4,msg:&#039;Generic Path Recursion1 denied&#039;"
#SecFilterSelective THE_REQUEST "\.\|\./\.\|\./\.\|" "id:300005,rev:1,severity:4,msg:&#039;Generic Path Recursion2 denied&#039;"
#SecFilterSelective THE_REQUEST "\.\.\./" "id:300006,rev:1,severity:4,msg:&#039;Bogus Path denied&#039;"
&nbsp;
#Generic PHP exploit signatures
#SecFilterSelective REQUEST_URI "&lt;\?php (chr|fwrite|fopen|system|echr|passthru|popen|proc_open|shell_exec|exec|proc_nice|proc_terminate|proc_get_status|proc_close|pfsockopen|leak|apache_child_terminate|posix_kill|posix_mkfifo|posix_setpgid|posix_setsid|posix_setuid|phpinfo)\(.*\)\;" "id:330002,rev:1,severity:4,msg:&#039;Generic PHP exploit pattern denied&#039;"
&nbsp;
#Prevent SQL injection in cookies
##SecFilterSelective COOKIE_VALUES "((select|grant|delete|insert|drop|alter|replace|truncate|update|create|rename|describe)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]+[[:space:]]+(from|into|table|database|index|view)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]|UNION SELECT.*\&#039;.*\&#039;.*,[0-9].*INTO.*FROM)" "id:300011,rev:1,severity:4,msg:&#039;Generic SQL injection in cookie&#039;"
&nbsp;
#Prevent SQL injection in UA
##SecFilterSelective HTTP_USER_AGENT "((select|grant|delete|insert|drop|alter|replace|truncate|update|create|rename|describe)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]+[[:space:]]+(from|into|table|database|index|view)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]|UNION SELECT.*\&#039;.*\&#039;.*,[0-9].*INTO.*FROM)" "id:300012,rev:1,severity:4,msg:&#039;Generic SQL injection in User Agent header&#039;"
&nbsp;
# Generic filter to prevent SQL injection attacks
# Understand that all SQL filters are very limited and are very difficult to prevent false postives and negatives.
# Please report false positives/negatives to mike@gotroot.com
#SecFilter "((select|grant|delete|insert|drop|alter|replace|truncate|update|create|rename|describe)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]+[[:space:]]+(from|into|table|database|index|view)[[:space:]]+[A-Z|a-z|0-9|\*| |\,]|UNION SELECT.*\&#039;.*\&#039;.*,[0-9].*INTO.*FROM)" "id:300013,rev:1,severity:4,msg:&#039;Generic SQL injection protection&#039;"
&nbsp;
#generic XSS PHP attack types
##SecFilterSelective REQUEST_URI "\.php\?" "chain,id:300010,rev:1,severity:4,msg:&#039;Generic PHP XSS exploit pattern denied&#039;"
#SecFilter "(javascript\:/(.*new\x20ActiveXObject.*Sh\.regwrite|.*window\.opener\.document\.body.\innerHTML=window\.opener\.document\.body\.innerHTML\.replace)|onmouseover=\&#039;javascript)"
&nbsp;
#Generic XSS filter
#please report false positives
##SecFilterSelective REQUEST_URI "!/mt\.cgi" "chain,msg:&#039;XSS2&#039;"
#SecFilter "&lt;[[:space:]]*(script|about|applet|activex|chrome)*&gt;.*(script|about|applet|activex|chrome)[[:space:]]*&gt;"
&nbsp;
#XSS in referrer and UA headers
##SecFilterSelective HTTP_REFERER|HTTP_USER_AGENT "&lt;[[:space:]]*(script|about|applet|activex|chrome)*&gt;.*(script|about|applet|activex|chrome)[[:space:]]*&gt;" "msg:&#039;XSS3&#039;"
&nbsp;
#HTTP header PHP code injection attacks
##SecFilterSelective HTTP_CLIENT_IP|HTTP_USER_AGENT|HTTP_Referer "(&lt;\?php|&lt;[[:space:]]?\?[[:space:]]?php|&lt;\? php)" "msg:&#039;PHP1&#039;"
&nbsp;
#Generic PHP remote file injection
##SecFilterSelective REQUEST_URI "!(/do_command)" "chain,msg:&#039;PHP2&#039;"
##SecFilterSelective REQUEST_URI "\.php\?.*=(https?|ftp)\:/.*(cmd|command)="
&nbsp;
#script, perl, etc. code in HTTP_Referer string
##SecFilterSelective HTTP_Referer "\#\!.*/" "msg:&#039;perl script1&#039;"
&nbsp;
#remote file inclusion generic attack signature
#SecFilterSelective THE_REQUEST  "\.(dat|gif|jpg|png|bmp|txt|vir|dot)\?" "chain,msg:&#039;remote 1&#039;"
#SecFilter "((name|pm_path|pagina|path|include_location|root|page|open)=(http|https|ftp)|(cmd|command|inc)=)"
&nbsp;
#remote file inclusion generic attack signature
#SecFilterSelective THE_REQUEST  "\.(dat|gif|jpg|png|bmp|txt|vir|dot)\?\&amp;(cmd|command|inc|name)=" "msg:&#039;remote2&#039;"
&nbsp;
#remote file inclusion generic attack signature
#SecFilterSelective ARGS  "\.(dat|gif|jpg|png|bmp|txt|vir|dot)" "chain,msg:&#039;file inclusion1&#039;"
#SecFilter "\?\&amp;(cmd|inc|name)="
&nbsp;
#remote file inclusion generic attack signature
#SecFilterSelective ARGS  "\.(dat|gif|jpg|png|bmp|txt|vir|dot)\?\&amp;(cmd|inc|name)=" "msg:&#039;file inclusion2&#039;"
&nbsp;
#remote file inclusion generic attack signature
#SecFilterSelective REQUEST_URI  "\.php\?.*=(http|https|ftp)\:/.*\?&amp;cmd=" "msg:&#039;file inclusion3&#039;"
&nbsp;
#Bogus file extensions generic signature
#SecFilterSelective THE_REQUEST  "[A-Za-z0-9]\.(gif|jpg|png|bmp)\.txt" "msg:&#039;file extension&#039;"
&nbsp;
#PHP remote path attach generic signature
#SecFilterSelective REQUEST_URI  "\.ph(p(3|4)?).*path=(http|https|ftp)\:/" "msg:&#039;remote path1&#039;"
#SecFilterSelective REQUEST_URI  "\.php.*path=(http|https|ftp)\:/" "msg:&#039;remote path2&#039;"
&nbsp;
#generic php attack sigs
#SecFilterSelective REQUEST_URI "(&amp;(cmd|command)=(id|uname)\x20|cmd\?(cmd|command)=|(spy|cmd|cmd_out|sh)\.(gif|jpg|png|bmp|txt)\?&amp;(cmd|command)=|\.php\?&amp;(cmd|command)=)" "msg:&#039;php attack1&#039;"
&nbsp;
# WEB-MISC apache directory disclosure attempt
#SecFilterSelective THE_REQUEST "////" "msg:&#039;apache directory disclosure&#039;"
&nbsp;
#PHP defenses
##SecFilterSelective ARG_PHPSESSID "!^$" "msg:&#039;something in phpsessid&#039;"
##SecFilterSelective COOKIE_PHPSESSID "!^$" "msg:&#039;something in cookie phpsessid&#039;"
&nbsp;
#PHP defenses
##SecFilterSelective COOKIE_ASKAPACHEID "!^[0-9a-z]*$" "msg:&#039;bad value for cookie&#039;"
&nbsp;
#cross site scripting attempt TYPE + JAVASCRIPT
##SecFilterSelective THE_REQUEST "TYPE\s*=\s*[\&#039;\"]text\/javascript" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt STYLE + JAVASCRIPT
##SecFilterSelective THE_REQUEST "TYPE\s*=\s*[\&#039;\"]application\/x-javascript" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt STYLE + JSCRIPT
##SecFilterSelective THE_REQUEST "TYPE\s*=\s*[\&#039;\"]text\/jscript" "msg:&#039;cross-site1&#039;"
&nbsp;
# cross site scripting attempt STYLE + VBSCRIPT
##SecFilterSelective THE_REQUEST "TYPE\s*=\s*[\&#039;\"]text\/vbscript" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt STYLE + VBSCRIPT
##SecFilterSelective THE_REQUEST "TYPE\s*=\s*[\&#039;\"]application\/x-vbscript" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt STYLE + ECMACRIPT
##SecFilterSelective THE_REQUEST "TYPE\s*=\s*[\&#039;\"]text\/ecmascript" "msg:&#039;cross-site1&#039;"
&nbsp;
# cross site scripting attempt STYLE + EXPRESSION
##SecFilterSelective THE_REQUEST "STYLE[\s]*=[\s]*[^&gt;]expression[\s]*\(" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt STYLE + EXPRESSION
##SecFilterSelective THE_REQUEST "[\s]*expression[\s]*\([^}]}[\s]*&lt;\/STYLE&gt;" "msg:&#039;cross-site1&#039;"
&nbsp;
# cross site scripting attempt using XML
##SecFilterSelective THE_REQUEST "&lt;!\[CDATA\[&lt;\]\]&gt;SCRIPT" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt executing hidden Javascript
##SecFilterSelective THE_REQUEST "eval[\s]*\([\s]*[^\.]\.innerHTML[\s]*\)" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt executing hidden Javascript
##SecFilterSelective THE_REQUEST "window\.execScript[\s]*\(" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting attempt to execute Javascript code
###SecFilterSelective THE_REQUEST "/(((URL|SRC|HREF|LOWSRC)[\s]*=)|(url[\s]*[\(]))[\s]*[\&#039;\"]*javascript[\:]" "msg:&#039;cross-site1&#039;"
&nbsp;
#cross site scripting HTML Image tag set to javascript attempt
#SecFilterSelective THE_REQUEST "img src=javascript" "msg:&#039;cross-site1&#039;"
&nbsp;
#Fake image file shell attacvk
#SecFilterSelective HTTP_Content-Type "image/.*" "msg:&#039;image shell 1&#039;"
#SecFilterSelective POST_PAYLOAD "chr\(" "msg:&#039;image shell2&#039;"
&nbsp;
#bogus graphics file
#SecFilterSelective HTTP_Content-Disposition "\.php"  "chain,msg:&#039;bogus graphics&#039;"
#SecFilterSelective HTTP_Content-Type "(image/gif|image/jpg|image/png|image/bmp)"
&nbsp;
# Allow only letters, digits, underscore, and square brackets (for arrays)
# in variable names#
#SecFilterSelective ARGS_NAMES "!^[][a-zA-Z0-9_]+$"
&nbsp;
#---------------------------------------------
# reject keywords that appear in POST or GET
#=============================================
SecFilterSignatureAction "nolog,auditlog,deny,severity:6,status:403"
&nbsp;
SecFilterSelective REQUEST_URI  "^/.*/wp-comments-post\.php" "id:50200,msg:&#039;WORDPRESS SPAM bad wp-comments-post location&#039;"
&nbsp;
&lt;files wp-comments-post.php&gt;
# fail for empty comment fields
SecFilterSelective "ARG_comment_post_ID|ARG_submit" "^$" "id:50300,msg:&#039;WORDPRESS SPAM MISSING comment_post_ID&#039;"
SecFilterSelective "ARG_comment_post_ID" "!^[0-9]{1,6}$" "id:50301,msg:&#039;WORDPRESS SPAM BAD comment_post_ID&#039;"
SecFilterSelective "HTTP_Cookie" "^$" "id:50302,msg:&#039;WORDPRESS SPAM No cookie&#039;"
&nbsp;
##SecFilterSelective "comment_post_DI" "^$" "id:50310,msg:&#039;WORDPRESS SPAM MISSING comment_post_DI&#039;"
##SecFilterSelective "comment_post_DI" "!^[0-9]{1,2}$" "id:50311,msg:&#039;WORDPRESS SPAM MISSING comment_post_DI&#039;"
&lt;/files&gt;
&lt;pre&gt;
&nbsp;
&lt;h2&gt;MODSEC Continued.. Custom Anti-Spam (WordPress) I made&lt;/h2&gt;
&lt;pre&gt;
SecFilterSignatureAction "nolog,noauditlog,deny,severity:6,redirect:http://www.askapache.com/feed/"
SecFilterSelective ARGS|THE_REQUEST "00bp\.com|360\.yahoo|987mb\.com|Ambien|American airline" "id:50010,msg:&#039;SPAM 10&#039;
SecFilterSelective ARGS|THE_REQUEST "Ativan|Caresoprodol|Darvocet|Ephedra|Ephedrine" "id:50011,msg:&#039;SPAM 11&#039;
SecFilterSelective ARGS|THE_REQUEST "Gambling|Lexapro|Tramadol|Venlafaxine" "id:50012,msg:&#039;SPAM 12&#039;
SecFilterSelective ARGS|THE_REQUEST "\[URL=|abgood|acura|acyclovir|adderall" "id:50013,msg:&#039;SPAM 13&#039;
SecFilterSelective ARGS|THE_REQUEST "adipex|alcohol|alprazolam|amateur|amrit" "id:50014,msg:&#039;SPAM 14&#039;
SecFilterSelective ARGS|THE_REQUEST "anal sex|analfinder|angelina jolie|asshole|axspace\.com" "id:50015,msg:&#039;SPAM 15&#039;
SecFilterSelective ARGS|THE_REQUEST "baccarat|bankrupt|bikini|biotic|black jack|blowjob" "id:50016,msg:&#039;SPAM 16&#039;
SecFilterSelective ARGS|THE_REQUEST "blackjack|blog\.360|brutality|buddhism|butalbital" "id:50017,msg:&#039;SPAM 17&#039;
SecFilterSelective ARGS|THE_REQUEST "cadillac|canalis|card credit|card stud|carisoprodol" "id:50018,msg:&#039;SPAM 18&#039;
SecFilterSelective ARGS|THE_REQUEST "carmen|cash advance|cash credit|casino|catch\.com" "id:50019,msg:&#039;SPAM 19&#039;
SecFilterSelective ARGS|THE_REQUEST "celebrex|celexa|cellulite|cheap|cheerleader" "id:50020,msg:&#039;SPAM 20&#039;
SecFilterSelective ARGS|THE_REQUEST "chevrolet|child abuse|cialis|cigarette|cipro" "id:50021,msg:&#039;SPAM 21&#039;
SecFilterSelective ARGS|THE_REQUEST "citroen|claritin|cleavage|clomid|codeine" "id:50022,msg:&#039;SPAM 22&#039;
SecFilterSelective ARGS|THE_REQUEST "consulting23|craps online|credit card|credit debt|crestor" "id:50023,msg:&#039;SPAM 23&#039;
SecFilterSelective ARGS|THE_REQUEST "dealership|debt free|desnudas|diazepam|dick" "id:50024,msg:&#039;SPAM 24&#039;
SecFilterSelective ARGS|THE_REQUEST "dildo|drugstore|earrings|endometrioma|endowment" "id:50025,msg:&#039;SPAM 25&#039;
SecFilterSelective ARGS|THE_REQUEST "erotic|estrogen|fioricet|francaise|freehost\.com" "id:50026,msg:&#039;SPAM 26&#039;
SecFilterSelective ARGS|THE_REQUEST "freehostia|freemb\.com|fuck|geocities\.com|hacking myspace" "id:50027,msg:&#039;SPAM 27&#039;
SecFilterSelective ARGS|THE_REQUEST "holdem|honda|hotels|hydrocodone|hypnotic" "id:50028,msg:&#039;SPAM 28&#039;
SecFilterSelective ARGS|THE_REQUEST "hyundai|implants|incest|instant approval|insurance" "id:50029,msg:&#039;SPAM 29&#039;
SecFilterSelective ARGS|THE_REQUEST "interracial|jaguar|jenny movie|johanson|kasino" "id:50030,msg:&#039;SPAM 30&#039;
SecFilterSelective ARGS|THE_REQUEST "lesbian|levitra|lipitor|loan|lolita" "id:50031,msg:&#039;SPAM 31&#039;
SecFilterSelective ARGS|THE_REQUEST "lorazepam|lorcet|lyrics|madamic|majorette" "id:50032,msg:&#039;SPAM 32&#039;
SecFilterSelective ARGS|THE_REQUEST "malaria|mastercar|masturbate|masturbation|maturewomen" "id:50033,msg:&#039;SPAM 33&#039;
SecFilterSelective ARGS|THE_REQUEST "mazda|medication|medicine|megsfree5\.com|mercedes" "id:50034,msg:&#039;SPAM 34&#039;
SecFilterSelective ARGS|THE_REQUEST "meridia|metformin|mitsubishi|mortgage|myspace profile" "id:50035,msg:&#039;SPAM 35&#039;
SecFilterSelective ARGS|THE_REQUEST "naked|neocool|nexium|nimire\.com|nissan" "id:50036,msg:&#039;SPAM 36&#039;
SecFilterSelective ARGS|THE_REQUEST "nokia|nude|nudism|nymph|open toe" "id:50037,msg:&#039;SPAM 37&#039;
SecFilterSelective ARGS|THE_REQUEST "oprodol|orgasm|oxycodone|oxycontin|packages" "id:50038,msg:&#039;SPAM 38&#039;
SecFilterSelective ARGS|THE_REQUEST "painrelief|pantyhose|paxil|payday|penis" "id:50039,msg:&#039;SPAM 39&#039;
SecFilterSelective ARGS|THE_REQUEST "percocet|pharmacy|phentermine|phetermine|phpbb_root" "id:50040,msg:&#039;SPAM 40&#039;
SecFilterSelective ARGS|THE_REQUEST "pictaboo|pictorial|pills|pissing|play craps" "id:50041,msg:&#039;SPAM 41&#039;
SecFilterSelective ARGS|THE_REQUEST "playgirl|pocker web|poker|pontiac|poquer" "id:50042,msg:&#039;SPAM 42&#039;
SecFilterSelective ARGS|THE_REQUEST "porn|pounder|prescription|preteen|prevacid" "id:50043,msg:&#039;SPAM 43&#039;
SecFilterSelective ARGS|THE_REQUEST "price1|prilosec|propecia|proza|prozac" "id:50044,msg:&#039;SPAM 44&#039;
SecFilterSelective ARGS|THE_REQUEST "puddled|pussy|refinance|rentals|replica" "id:50045,msg:&#039;SPAM 45&#039;
SecFilterSelective ARGS|THE_REQUEST "ringtones|roulette|screensaver|seduced|sexual" "id:50046,msg:&#039;SPAM 46&#039;
SecFilterSelective ARGS|THE_REQUEST "sexy|shemale|shiloh|singulair|site-host" "id:50047,msg:&#039;SPAM 47&#039;
SecFilterSelective ARGS|THE_REQUEST "slot machine|slot maschine|slots machine|solpip\.com|soma" "id:50048,msg:&#039;SPAM 48&#039;
SecFilterSelective ARGS|THE_REQUEST "sperm|starlets|supplier|suzuki|tadalafil" "id:50049,msg:&#039;SPAM 49&#039;
SecFilterSelective ARGS|THE_REQUEST "toyota|tylenol|ultram|valium|viagra" "id:50050,msg:&#039;SPAM 50&#039;
SecFilterSelective ARGS|THE_REQUEST "vigora|vioxx|wallpaper|warez|webcam" "id:50051,msg:&#039;SPAM 51&#039;
SecFilterSelective ARGS|THE_REQUEST "webpages\.com|wellbutrin|whitesluts|wholesale|whore" "id:50052,msg:&#039;SPAM 52&#039;
SecFilterSelective ARGS|THE_REQUEST "windshield|xanax|xenical|y lohan|yourgirls" "id:50053,msg:&#039;SPAM 53&#039;
SecFilterSelective ARGS|THE_REQUEST "youtube\.com|zantac|sex offenders|hotgay|Zoloft|celtic women" "id:50054,msg:&#039;SPAM 54&#039;
SecFilterSelective ARGS|THE_REQUEST "dollhouse|freehot|kardashian|oralsex" "id:50055,msg:&#039;SPAM 55&#039;
SecFilterSelective ARGS|THE_REQUEST "freeimghost" "id:50056,msg:&#039;SPAM 56&#039;</pre>





<h2>Unreleased AskApache Lightning code - caching plugin for WordPress</h2>
<pre>RewriteEngine On
RewriteBase /
&nbsp;
RewriteCond %{REQUEST_URI} ^/(stats/|missing\.html|failed_auth\.html|test/).* [NC,OR]
RewriteCond %{ENV:REDIRECT_STATUS} =200
RewriteRule .* - [L]
&nbsp;
RewriteCond %{HTTP_HOST} !=www.askapache.com
RewriteCond %{HTTP_HOST} !=z.askapache.com
RewriteRule .? http://www.askapache.com%{REQUEST_URI}%{QUERY_STRING} [R=301,L]
&nbsp;
#RewriteCond %{HTTPS} =on
#RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ /(wp-login.php|wp-admin)(.*)\ HTTP/ [NC]
#RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.*)\ HTTP/ [NC]
#RewriteRule .* http://www.askapache.com/$1 [R=301,L]
&nbsp;
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.+)%20(.+)\ HTTP/ [NC]
RewriteRule .* http://www.askapache.com/%1-%2 [R=301,L]
&nbsp;
RewriteCond %{THE_REQUEST} ^GET\ /valid-html/.*\ HTTP/ [NC]
RewriteCond %{HTTP_REFERER} ^https?://www.askapache.com(.+).*$ [NC]
RewriteRule .* http://validator.w3.org/check?uri=http://www.askapache.com%1;ss=1;outline=1;debug [R=307,L,NE]
&nbsp;
RewriteCond %{THE_REQUEST} ^GET\ /valid-css/.*\ HTTP/ [NC]
RewriteRule .* http://jigsaw.w3.org/css-validator/validator?uri=z.askapache.com/z/c/apache-10.css [R=301,L]
&nbsp;
RewriteCond %{THE_REQUEST} ^GET\ /search/.*\ HTTP/ [NC]
RewriteCond %{QUERY_STRING} ^s=(.+)$ [NC]
RewriteRule .* http://www.askapache.com/search/%1? [R=302,L]
&nbsp;
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/X%{REQUEST_URI}index.html -f
RewriteRule ^(.*)$ /X%{REQUEST_URI}index.html [L]
&nbsp;
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{DOCUMENT_ROOT}/X%{REQUEST_URI} -f
RewriteRule ^(.*)$ /X%{REQUEST_URI} [L]</pre>



<h2>Passing Parameters to CGI through HTTP Headers</h2>
<p>This deserves a note.. this trick lets you bypass so many hosting environment restrictions it's not even funny... like you can run bash as your webserver instead of apache!  (kinda...)</p>
<pre>RewriteCond %{REQUEST_URI} ^/cgi-bin/(hash|java)\.cgi$ [NC]
RewriteCond %{HTTP:P3P} ^(([^:]+):(.+))$ [NC]
RewriteRule .* - [E=HTTP_JS:%{HTTP:P3P},E=HTTP_US:%2,E=HTTP_PA:%3]</pre>



<h2>Redirect to FeedBurner</h2>
<p>Yes.. I was the first to do this (parse the real rewrites internally in wordpress for no bypassing possibilities)... </p>
<pre>#RewriteCond %{REQUEST_URI} ^/feed/.*?$ [NC,OR]
#RewriteCond %{HTTP_REFERER} ^https?://www.askapache.com/wp-admin(.+).*$ [NC]
RewriteCond %{HTTP_USER_AGENT} FeedBurner [NC]
RewriteRule .* - [S=1]
&nbsp;
RewriteCond %{REQUEST_URI} ^/(feed|rdf|rss|rss2|atom).* [NC,OR]
RewriteCond %{REQUEST_URI} ^/wp-(feed|rdf|rss|rss2|atom).* [NC,OR]
RewriteCond %{REQUEST_FILENAME} ^.*/(wp-atom|wp-feed|wp-rdf|wp-rss|wp-rss2)\.php$ [NC,OR]
RewriteCond %{REQUEST_FILENAME} ^.*/wp-includes/feed[^\.]*\.php$ [NC,OR]
RewriteCond %{QUERY_STRING} .*(feed|rdf|rss|rss2|atom).* [NC]
RewriteRule .* http://feeds.askapache.com/apache/htaccess? [R=302,L]</pre>
































<h2>More Unreleased Caching Tests</h2>
<pre># +ASKAPACHE CRAZYCACHE 2.3
#######################################################
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# +ACACHE RULES
# +RULE
RewriteCond %{THE_REQUEST} ^(GET|HEAD)\ //?(.+)\.rdf\ HTTP/ [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-cache/%2.html/index.rdf -f
RewriteRule ^(.+)\.rdf$ /wp-cache/%2.html/index.rdf [L,S=3]
&nbsp;
RewriteCond %{QUERY_STRING} !^.*cacheit.* [NC]
#RewriteCond %{HTTP_USER_AGENT} W3C_Validator [OR,NC]
#RewriteCond %{REMOTE_ADDR} = [OR]
&nbsp;
RewriteCond %{REQUEST_METHOD} =POST [OR]
RewriteCond %{THE_REQUEST} ^$ [OR]
RewriteCond %{QUERY_STRING} nocache [OR]
RewriteCond %{REMOTE_ADDR} = [OR]
RewriteCond %{HTTP_COOKIE} ^.*wordpress_logged_in_.*$ [NC]
RewriteRule .+ - [S=2]
&nbsp;
RewriteCond %{DOCUMENT_ROOT}/wp-cache%{REQUEST_URI} !-d
RewriteRule .+ - [S=1]
&nbsp;
RewriteCond %{DOCUMENT_ROOT}/wp-cache%{REQUEST_URI}/index.html -f
RewriteRule .+ /wp-cache%{REQUEST_URI}/index.html [L]
# -RULE
# -ACACHE RULES
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
#######################################################
# -ASKAPACHE CRAZYCACHE 2.3
&nbsp;
# +ASKAPACHE CRAZYCACHE 2.3
#######################################################
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
# +ACACHE RULES
# +RULE
FileETag None
AddOutputFilterByType DEFLATE text/html
&nbsp;
AddType &#039;text/html; charset=UTF-8&#039; .html
&nbsp;
Header set P3P "policyref=\"http://www.askapache.com/w3c/p3p.xml\""
Header set X-Pingback "http://www.askapache.com/xmlrpc.php"
Header set Content-Language "en-US"
Header set Vary "Accept-Encoding,Accept"
&nbsp;
&lt;ifModule mod_expires.c&gt;
ExpiresActive On
ExpiresDefault M7200
&lt;/ifModule&gt;
# -RULE
# -ACACHE RULES
# - - - - - - - - - - - - - - - - - - - - - - - - - - -
#               __                          __
#   ____ ______/ /______ _____  ____ ______/ /_  ___
#  / __ `/ ___/ //_/ __ `/ __ \/ __ `/ ___/ __ \/ _ \
# / /_/ (__  ) ,&lt; / /_/ / /_/ / /_/ / /__/ / / /  __/
# \__,_/____/_/|_|\__,_/ .___/\__,_/\___/_/ /_/\___/
#                     /_/
#######################################################
# -ASKAPACHE CRAZYCACHE 2.3
&nbsp;
Options +IndexesOptions +FollowSymLinks
AddHandler application/x-httpd-php .php
&nbsp;
RewriteEngine On
RewriteBase /
RewriteCond %{QUERY_STRING} !^tyy+$ [NC]
RewriteCond %{REMOTE_USER} ^(.+)$
RewriteRule ^(.*)$ $1/-%1 [R=302,L]
Options +FollowSymLinks
DirectoryIndex index.php
ErrorDocument 404 /cgi-bin/pro/index.php
&nbsp;
AuthName "Protection"
AuthUserFile /home/askapache/sites/askapache.com/.htpasswda1
AuthGroupFile /dev/null
AuthType Basic
Require valid-user
Satisfy Any
&nbsp;
&lt;ifModule mod_security.c&gt;
SecFilterEngine Off
&lt;/ifModule&gt;
Options +ExecCGI -Indexes -Includes +FollowSymLinks
Order Deny,Allow
Deny from All
Allow from 208.113.134.190 64.111.114.111  env=REDIRECT_STATUS
&nbsp;
#SetEnvIf Remote_Addr ^$ MODSEC_ENABLE=Off
#SetEnvIf Server_Addr ^$ MODSEC_ENABLE=Off
#SetEnvIf Remote_Addr ^({SERVER_ADDR}e)$ GOOD=$1
#SetEnvIf Server_Addr GOOD R</pre>


<h2>Default HTACCESS</h2>
<pre>#
# Directives controlling the display of server-generated directory listings.
#
# Required modules: mod_autoindex, mod_alias
#
# To see the listing of a directory, the Options directive for the
# directory must include "Indexes", and the directory must not contain
# a file matching those listed in the DirectoryIndex directive.
#
Options +Indexes +MultiViews -ExecCGI +FollowSymLinks
DirectoryIndex index.html
&nbsp;
#
#
# IndexOptions: Controls the appearance of server-generated directory
# listings.
#
IndexOptions FancyIndexing IconHeight=22 IconWidth=20 IgnoreClient NameWidth=* DescriptionWidth=* ScanHTMLTitles SuppressLastModified XHTML FoldersFirst SuppressHTMLPreamble
&nbsp;
#
# AddIcon* directives tell the server which icon to show for different
# files or filename extensions.  These are only displayed for
# FancyIndexed directories.
#
&nbsp;
AddIconByEncoding (CMP,http://z.askapache.com/i/s/compressed.gif) x-compress x-gzip
&nbsp;
AddIconByType (IMG,http://z.askapache.com/i/s/image.gif) image/*
AddIconByType (SND,http://z.askapache.com/i/s/sound2.gif) audio/*
AddIconByType (TXT,http://z.askapache.com/i/s/text.gif) text/*
AddIconByType (VID,http://z.askapache.com/i/s/movie.gif) video/*
&nbsp;
AddIcon http://z.askapache.com/i/s/hand.right.gif README
AddIcon http://z.askapache.com/i/s/folder.gif ^^DIRECTORY^^
AddIcon http://z.askapache.com/i/s/dir.png ^^DIRECTORY^^
AddIcon http://z.askapache.com/i/s/blank.gif ^^BLANKICON^^
AddDescription "100 Continue" 100* 100/index.html
AddDescription "101 Switching Protocols" 101* 101/index.html
AddDescription "102 Processing" 102* 102/index.html
AddDescription "200 OK" 200* 200/index.html
AddDescription "201 Created" 201* 201/index.html
AddDescription "202 Accepted" 202* 202/index.html
AddDescription "203 Non-Authoritative Information" 203* 203/index.html
AddDescription "204 No Content" 204* 204/index.html
AddDescription "205 Reset Content" 205* 205/index.html
AddDescription "206 Partial Content" 206* 206/index.html
AddDescription "207 Multi-Status" 207* 207/index.html
AddDescription "300 Multiple Choices" 300* 300/index.html
AddDescription "301 Moved Permanently" 301* 301/index.html
AddDescription "302 Found" 302* 302/index.html
AddDescription "303 See Other" 303* 303/index.html
AddDescription "304 Not Modified" 304* 304/index.html
AddDescription "305 Use Proxy" 305* 305/index.html
AddDescription "306 unused" 306* 306/index.html
AddDescription "307 Temporary Redirect" 307* 307/index.html
AddDescription "400 Bad Request" 400* 400/index.html
AddDescription "401 Authorization Required" 401* 401/index.html
AddDescription "402 Payment Required" 402* 402/index.html
AddDescription "403 Forbidden" 403* 403/index.html
AddDescription "404 Not Found" 404* 404/index.html
AddDescription "405 Method Not Allowed" 405* 405/index.html
AddDescription "406 Not Acceptable" 406* 406/index.html
AddDescription "407 Proxy Authentication Required" 407* 407/index.html
AddDescription "408 Request Time-out" 408* 408/index.html
AddDescription "409 Conflict" 409* 409/index.html
AddDescription "410 Gone" 410* 410/index.html
AddDescription "411 Length Required" 411* 411/index.html
AddDescription "412 Precondition Failed" 412* 412/index.html
AddDescription "413 Request Entity Too Large" 413* 413/index.html
AddDescription "414 Request-URI Too Large" 414* 414/index.html
AddDescription "415 Unsupported Media Type" 415* 415/index.html
AddDescription "416 Requested Range Not Satisfiable" 416* 416/index.html
AddDescription "417 Expectation Failed" 417* 417/index.html
AddDescription "418 unused" 418* 418/index.html
AddDescription "419 unused" 419* 419/index.html
AddDescription "420 unused" 420* 420/index.html
AddDescription "421 unused" 421* 421/index.html
AddDescription "422 Unprocessable Entity" 422* 422/index.html
AddDescription "423 Locked" 423* 423/index.html
AddDescription "424 Failed Dependency" 424* 424/index.html
AddDescription "425 No code" 425* 425/index.html
AddDescription "426 Upgrade Required" 426* 426/index.html
AddDescription "500 Internal Server Error" 500* 500/index.html
AddDescription "501 Method Not Implemented" 501* 501/index.html
AddDescription "502 Bad Gateway" 502* 502/index.html
AddDescription "503 Service Temporarily Unavailable" 503* 503/index.html
AddDescription "504 Gateway Time-out" 504* 504/index.html
AddDescription "505 HTTP Version Not Supported" 505* 505/index.html
AddDescription "506 Variant Also Negotiates" 506* 506/index.html
AddDescription "507 Insufficient Storage" 507* 507/index.html
AddDescription "508 unused" 508* 508/index.html
AddDescription "509 unused" 509* 509/index.html
AddDescription "510 Not Extended" 510* 510/index.html
AddDescription ".htaccess ErrorDocuments" *
&nbsp;
#
# HeaderName is the name of a file which should be prepended to
# directory indexes.
ReadmeName /X/error/README.html
HeaderName /X/error/HEADER.html
&nbsp;
# DefaultIcon is which icon to show for where none is explicitly set.
DefaultIcon http://z.askapache.com/i/s/generic.gif</pre>


<h2>Ok I'm done commenting..</h2>
<pre>#
# IndexIgnore is a set of filenames which directory indexing should ignore
# and not include in the listing.  Shell-style wildcarding is permitted.
#
IndexIgnore .??*  *_notes *~
RewriteEngine On
RewriteCond %{HTTPS} !=on [NC]
RewriteRule .* https://www.askapache.com%{REQUEST_URI}
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},E=REMOTE_USER:%{HTTP:Authorization}]
&nbsp;
#RewriteCond %{QUERY_STRING} openid.mode=authorize
#RewriteCond %{REQUEST_URI} ^/openid.*$ [NC]
#RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},E=REMOTE_USER:%{HTTP:Authorization}]
Options +FollowSymLinks
DirectoryIndex index.html
&nbsp;
#SetEnvIfNoCase ^Cookie$ "(.*)" HTTP_MY_COOKIE=$1
#SetEnvIfNoCase Remote_Addr "(.*)" HTTP_MY_REMOTE_ADDR=$1
ExpiresActive Off
FileETag None
Header unset Connection
Header set Connection "close"
Header unset Last-Modified
Header unset ETag
Header unset Accept-Ranges
Header unset Vary
Header unset Content-Type
Header unset X-Pingback
Header unset P3P
#Header add RouterBits "%D %t"
#Header add Location "http://www.askapache.com/feed/"
#Header add Found "http://askapache.com/feed/"
#Header add Content-Location "http://www.askapache.com/feed/"
#Header add Refresh "http://www.askapache.com/feed/"
#Header set Hi "%{HTTP_MY_REMOTE_ADDR}e"
### Section 1: Global Environment
#
# The directives in this section affect the overall operation of Apache,
# such as the number of concurrent requests it can handle or where it
# can find its configuration files.
#
#
# TZ: Your address, where problems with the server should be
# e-mailed.  This address appears on some server-generated pages, such
# as error documents.  e.g. admin@your-domain.com
#
SetEnv TZ America/Indianapolis
&nbsp;
#
# ServerAdmin: Your address, where problems with the server should be
# e-mailed.  This address appears on some server-generated pages, such
# as error documents.  e.g. admin@your-domain.com
#
SetEnv SERVER_ADMIN webmaster@askapache.com
&nbsp;
#
# Possible values for the Options directive are "None", "All",
# or any combination of:
#   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
#
# The Options directive is both complicated and important.  Please see
# http://httpd.apache.org/docs/2.0/mod/core.html#options
# for more information.
#
Options  +FollowSymLinks -ExecCGI -Indexes -Includes -MultiViews
&nbsp;
#
# DirectoryIndex: sets the file that Apache will serve if a directory
# is requested.
#
DirectoryIndex index.html index.php /index.php
&nbsp;
#
# The following lines prevent .htaccess and .htpasswd files from being
# viewed by Web clients.
#
&lt;filesMatch "^\.ht"&gt;
    Order allow,deny
    Deny from all
  Satisfy All
&lt;/filesMatch&gt;
&nbsp;
#
# DefaultType: the default MIME type the server will use for a document
# if it cannot otherwise determine one, such as from filename extensions.
# If your server contains mostly text or HTML documents, "text/plain" is
# a good value.  If most of your content is binary, such as applications
# or images, you may want to use "application/octet-stream" instead to
# keep browsers from trying to display binary files as though they are
# text.
#
DefaultType text/html
&nbsp;
#
# Optionally add a line containing the server version and virtual host
# name to server-generated pages (internal error documents, FTP directory
# listings, mod_status and mod_info output etc., but not CGI generated
# documents or custom error documents).
# Set to "EMail" to also include a mailto: link to the ServerAdmin.
# Set to one of:  On | Off | EMail
#
ServerSignature Off
&nbsp;
##############################################
#           HEADERS and CACHING              #
##############################################
Header unset Pragma
Header unset Last-Modified
FileETag None
&nbsp;
Redirect 400 /e/400
Redirect 401 /e/401
Redirect 402 /e/402
Redirect 403 /e/403
Redirect 404 /e/404
Redirect 405 /e/405
Redirect 406 /e/406
Redirect 407 /e/407
Redirect 408 /e/408
Redirect 409 /e/409
Redirect 410 /e/410
Redirect 411 /e/411
Redirect 412 /e/412
Redirect 413 /e/413
Redirect 414 /e/414
Redirect 415 /e/415
Redirect 416 /e/416
Redirect 417 /e/417
Redirect 418 /e/418
Redirect 419 /e/419
Redirect 420 /e/420
Redirect 421 /e/421
Redirect 422 /e/422
Redirect 423 /e/423
Redirect 424 /e/424
Redirect 425 /e/425
Redirect 426 /e/426
Redirect 500 /e/500
Redirect 501 /e/501
Redirect 502 /e/502
Redirect 503 /e/503
Redirect 504 /e/504
Redirect 505 /e/505
Redirect 506 /e/506
Redirect 507 /e/507
Redirect 508 /e/508
Redirect 509 /e/509
Redirect 510 /e/510
&nbsp;
#
# Redirect allows you to tell clients about documents which used to exist in
# your server&#039;s namespace, but do not anymore. This allows you to tell the
# clients where to look for the relocated document.
##############################################
#          PERMANENT REDIRECTS               #
##############################################
Redirect 301 /12-lessons-for-those-afraid-of-css.html http://www.askapache.com/css/12-lessons-for-those-afraid-of-css.html
Redirect 301 /2006/htaccess/htaccesselite-ultimate-htaccess-article.html http://www.askapache.com/htaccess/apache-htaccess.html
Redirect 301 /2007/phpbb/sending-post-form-data-with-php-curl.html http://www.askapache.com/htaccess/sending-post-form-data-with-php-curl.html
Redirect 301 /2007/webmaster/custom-phpini-with-fastcgi-on-dreamhost.html http://www.askapache.com/dreamhost/custom-phpini-with-fastcgi-on-dreamhost.html
Redirect 301 /2007/webmaster/custom-phpini-with-fastcgi-on-dreamhost.html http://www.askapache.com/dreamhost/custom-phpini-with-fastcgi-on-dreamhost.html
Redirect 301 /2007/webmaster/php-and-ajax-shell-console.html http://www.askapache.com/tools/php-and-ajax-shell-console.html
Redirect 301 /27-request-methods-for-use-with-apache-and-rewritecond-and-htaccess.html http://www.askapache.com/htaccess/27-request-methods-for-use-with-apache-and-rewritecond-and-htaccess.html
Redirect 301 /404-google-wordpress-plugin.html http://www.askapache.com/seo/404-google-wordpress-plugin.html
Redirect 301 /503-service-temporarily-unavailable.html http://www.askapache.com/htaccess/503-service-temporarily-unavailable.html
Redirect 301 /Overview-about.rdf http://www.askapache.com/askapache-home.rdf
Redirect 301 /abbr-acronym.html http://www.askapache.com/xhtml/abbr-acronym.html
Redirect 301 /adsense-robots.html http://www.askapache.com/google/adsense-robots.html
Redirect 301 /alexa-toolbar-firefox.html http://www.askapache.com/tools/alexa-toolbar-firefox.html
Redirect 301 /allowing-access-from-1-static-ip-and-deny-the-rest.html http://www.askapache.com/htaccess/apache-htaccess.html
Redirect 301 /anti-virus-spyware-rootkit.html http://www.askapache.com/security/anti-virus-spyware-rootkit.html
Redirect 301 /apache-ssl-in-htaccess-examples.html http://www.askapache.com/htaccess/apache-ssl-in-htaccess-examples.html
Redirect 301 /awk-tutorial.html http://www.askapache.com/awk/awk-tutorial.html
Redirect 301 /best-adsense-optimization.html http://www.askapache.com/wordpress/best-adsense-optimization.html
Redirect 301 /commonly-used-htaccess-code-examples.html http://www.askapache.com/htaccess/commonly-used-htaccess-code-examples.html
Redirect 301 /css-background-image-sprite.html http://www.askapache.com/css/css-background-image-sprite.html
Redirect 301 /css-browser-screenshots.html http://www.askapache.com/tools/css-browser-screenshots.html
Redirect 301 /css-class-example.html http://www.askapache.com/css/css-class-example.html
Redirect 301 /curl-multi-downloads.html http://www.askapache.com/php/curl-multi-downloads.html
Redirect 301 /custom-boot-menu-in-windows-xp.html http://www.askapache.com/windows/custom-boot-menu-in-windows-xp.html
Redirect 301 /donate http://www.dreamhost.com/donate.cgi?id=8261
Redirect 301 /donate/ http://www.dreamhost.com/donate.cgi?id=8261
Redirect 301 /htaccess.txt http://z.askapache.com/p/htaccess.txt
Redirect 301 /htaccess/404-errorpages.html http://www.askapache.com/seo/google-ajax-search-seo-tips.html
Redirect 301 /htaccess/feedsmith http://www.askapache.com/htaccess/feedsmith-htaccess.html
Redirect 301 /htaccess/http-status-codes.html http://www.askapache.com/htaccess/apache-status-code-headers-errordocument.html
Redirect 301 /htaccess/instruct-search-engines-to-come-back-to-site-after-you-finish-working-on-it.html http://www.askapache.com/htaccess/503-service-temporarily-unavailable.html
Redirect 301 /htaccess/speed-up-the-apache-web-server-with-configuration-hacks.html http://www.askapache.com/htaccess/apache-web-server-speed-configuration-hacks.html
Redirect 301 /instruct-search-engines-to-come-back-to-site-after-you-finish-working-on-it.html http://www.askapache.com/htaccess/503-service-temporarily-unavailable.html
Redirect 301 /security/bypassing-vlan.html http://www.askapache.com/security/hacking-vlan-switched-networks.html
Redirect 301 /security/bypassing-vlanbypassing-vlan.html http://www.askapache.com/security/hacking-vlan-switched-networks.html
Redirect 301 /security/rigging-the-dreamhost-site-of-the-month-contest.html http://www.askapache.com/dreamhost/rigging-the-dreamhost-site-of-the-month-contest.html
Redirect 301 /seo/tailrankcom-robot.html http://www.askapache.com/seo/tailrank-robot.html
Redirect 301 /webmaster/caching-tutorial-for-webmasters.html http://www.askapache.com/htaccess/caching-tutorial-for-webmasters.html
Redirect 301 /webmaster/lft-traceroute-tool.html http://www.askapache.com/tools/lft-traceroute-tool.html
&nbsp;
##############################################
#          PERMANENT REDIRECTMATCH           #
##############################################
#RedirectMatch 301 ^/&amp;(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/&amp;amp(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/([^/]+)//$ http://www.askapache.com/$1/
RedirectMatch 301 ^/(.+)/htaccesselite-ultimate-htaccess-article.html(.*) http://www.askapache.com/htaccess/apache-htaccess.html
RedirectMatch 301 ^/(.+)\.html/([a-z][a-z])/$ http://www.askapache.com/$1.html
RedirectMatch 301 ^/([\(]+)(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/([^9]*)9O1X.3y(.*)/(.*)$ http://www.askapache.com/$2
RedirectMatch 301 ^/.3y(.*)$ http://www.askapache.com/
RedirectMatch 301 ^/200([0-9])/([0-9])(.*)$ http://www.askapache.com/top-100/
RedirectMatch 301 ^/200([0-9])/([^01])(.*)$ http://www.askapache.com/$2$3
RedirectMatch 301 ^/about/glossary(.*)$ http://www.askapache.com/glossary$1
RedirectMatch 301 ^/apache-speed(.*)$ http://www.askapache.com/htaccess/apache-speed$1
RedirectMatch 301 ^/category/(.+)$ http://www.askapache.com/$1
RedirectMatch 301 ^/docs/(.*)$ http://askapache.info/$1
RedirectMatch 301 ^/htaccess/feedsmith-htaccess(.*) http://www.askapache.com/htaccess/redirecting-wordpress-feeds-to-feedburner.html
RedirectMatch 301 ^/robots-txt(.*)$ http://www.askapache.com/robots.txt
#RedirectMatch 301 ^/wp-content/uploads/(.*)$ http://z.askapache.com/uploads/$1
RedirectMatch 301 ^/z/(.+)$ http://z.askapache.com/$1
RedirectMatch 301 ^/(z|t|i|j|c|p)/(.*)$ http://z.askapache.com/$1/$2
RedirectMatch 301 ^/hosting/?$ http://www.askapache.com/hosting/
&nbsp;
##############################################
#          TEMPORARY REDIRECTMATCH           #
##############################################
RedirectMatch 307 ^/getflash/?$ http://www.adobe.com/shockwave/download/download.cgi?P1_Prod_Version=ShockwaveFlash
RedirectMatch 307 ^/dream/?$ http://www.askapache.com/dreamhost/
RedirectMatch 307 ^/(cse|apachecse|apachecsetest|apachesearch)/?$ http://www.google.com/coop/cse?cx=002660089121042511758%3Akk7rwc2gx0i
&nbsp;
#
# Commonly used filename extensions to character sets. You probably
# want to avoid clashes with the language extensions, unless you
# are good at carefully testing your setup after each change.
# See http://www.iana.org/assignments/character-sets for the
# official list of charset names and their respective RFCs.
#
AddDefaultCharset UTF-8
&nbsp;
#
# AddType allows you to add to or override the MIME configuration
# file mime.types for specific file types.
#
#
AddType &#039;application/rdf+xml; charset=UTF-8&#039; .rdf
AddType &#039;application/xhtml+xml; charset=UTF-8&#039; .xhtml
AddType &#039;application/xhtml+xml; charset=UTF-8&#039; .xhtml.gz
AddType &#039;text/html; charset=UTF-8&#039; .html
AddType &#039;text/html; charset=UTF-8&#039; .html.gz
AddType application/octet-stream .rar .chm .bz2 .tgz .msi .pdf .exe
AddType application/vnd.ms-excel .csv
AddType application/x-httpd-php-source .phps
AddType application/x-pilot .prc .pdb
AddType application/x-shockwave-flash .swf
AddType application/xrds+xml .xrdf
AddType text/plain .ini .sh .bsh .bash .awk .nawk .gawk .csh .var .c .in .h .asc .md5 .sha .sha1
AddType video/x-flv .flv
&nbsp;
#
# AddEncoding allows you to have certain browsers uncompress
# information on the fly. Note: Not all browsers support this.
# Despite the name similarity, the following Add* directives have nothing
# to do with the FancyIndexing customization directives above.
#
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
&nbsp;
#
# AddHandler allows you to map certain file extensions to "handlers":
# actions unrelated to filetype. These can be either built into the server
# or added with the Action directive (see below)
#
# To use CGI scripts outside of ScriptAliased directories:
# (You will also need to add "ExecCGI" to the "Options" directive.)
#
AddHandler php-cgi .php
&nbsp;
#
# Action lets you define media types that will execute a script whenever
# a matching file is called. This eliminates the need for repeated URL
# pathnames for oft-used CGI file processors.
# Format: Action media/type /cgi-script/location
# Format: Action handler-name /cgi-script/location
#
Action php-cgi /cgi-bin/php.cgi
&nbsp;
#
# Customizable error responses come in three flavors:
# 1) plain text 2) local redirects 3) external redirects
#
#100 Continue
#101 Switching Protocols
#102 Processing
#200 OK
#201 Created
#202 Accepted
#203 Non-Authoritative Information
#204 No Content
#205 Reset Content
#206 Partial Content
#207 Multi-Status
#300 Multiple Choices
#301 Moved Permanently
#302 Found
#303 See Other
#304 Not Modified
#305 Use Proxy
#306 unused
#307 Temporary Redirect
#400 Bad Request
#401 Authorization Required
#402 Payment Required
#403 Forbidden
#404 Not Found
#405 Method Not Allowed
#406 Not Acceptable
#407 Proxy Authentication Required
#408 Request Time-out
#409 Conflict
#410 Gone
#411 Length Required
#412 Precondition Failed
#413 Request Entity Too Large
#414 Request-URI Too Large
#415 Unsupported Media Type
#416 Requested Range Not Satisfiable
#417 Expectation Failed
#418 unused
#419 unused
#420 unused
#421 unused
#422 Unprocessable Entity
#423 Locked
#424 Failed Dependency
#425 No code
#426 Upgrade Required
#500 Internal Server Error
#501 Method Not Implemented
#502 Bad Gateway
#503 Service Temporarily Unavailable
#504 Gateway Time-out
#505 HTTP Version Not Supported
#506 Variant Also Negotiates
#507 Insufficient Storage
#508 unused
#509 unused
#510 Not Extended
&nbsp;
#ErrorDocument 100 /X/err/1/HTTP_CONTINUE.html
#ErrorDocument 101 /X/err/1/HTTP_SWITCHING_PROTOCOLS.html
#ErrorDocument 102 /X/err/1/HTTP_PROCESSING.html
&nbsp;
#ErrorDocument 200 /X/err/2/HTTP_OK.html
#ErrorDocument 201 /X/err/2/HTTP_CREATED.html
#ErrorDocument 202 /X/err/2/HTTP_ACCEPTED.html
#ErrorDocument 203 /X/err/2/HTTP_NON_AUTHORITATIVE.html
#ErrorDocument 204 /X/err/2/HTTP_NO_CONTENT.html
#ErrorDocument 205 /X/err/2/HTTP_RESET_CONTENT.html
#ErrorDocument 206 /X/err/2/HTTP_PARTIAL_CONTENT.html
#ErrorDocument 207 /X/err/2/HTTP_MULTI_STATUS.html
&nbsp;
#ErrorDocument 300 /X/err/HTTP_MULTIPLE_CHOICES.html
#ErrorDocument 301 /X/err/HTTP_MOVED_PERMANENTLY.html
#ErrorDocument 302 /X/err/HTTP_MOVED_TEMPORARILY.html
#ErrorDocument 303 /X/err/HTTP_SEE_OTHER.html
#ErrorDocument 304 /X/err/HTTP_NOT_MODIFIED.html
#ErrorDocument 305 /X/err/HTTP_USE_PROXY.html
#ErrorDocument 307 /X/err/HTTP_TEMPORARY_REDIRECT.html
#ErrorDocument 404 /X/err/HTTP_NOT_FOUND.html
&nbsp;
ErrorDocument 400 /X/err/4/HTTP_BAD_REQUEST.html
ErrorDocument 401 /X/err/4/HTTP_UNAUTHORIZED.html
ErrorDocument 402 /X/err/4/HTTP_PAYMENT_REQUIRED.html
ErrorDocument 403 /X/err/4/HTTP_FORBIDDEN.html
ErrorDocument 405 /X/err/4/HTTP_METHOD_NOT_ALLOWED.html
ErrorDocument 406 /X/err/4/HTTP_NOT_ACCEPTABLE.html
ErrorDocument 407 /X/err/4/HTTP_PROXY_AUTHENTICATION_REQUIRED.html
ErrorDocument 408 /X/err/4/HTTP_REQUEST_TIME_OUT.html
ErrorDocument 409 /X/err/4/HTTP_CONFLICT.html
ErrorDocument 410 /X/err/4/HTTP_GONE.html
ErrorDocument 411 /X/err/4/HTTP_LENGTH_REQUIRED.html
ErrorDocument 412 /X/err/4/HTTP_PRECONDITION_FAILED.html
ErrorDocument 413 /X/err/4/HTTP_REQUEST_ENTITY_TOO_LARGE.html
ErrorDocument 414 /X/err/4/HTTP_REQUEST_URI_TOO_LARGE.html
ErrorDocument 415 /X/err/4/TTP_UNSUPPORTED_MEDIA_TYPE.html
ErrorDocument 416 /X/err/4/HTTP_RANGE_NOT_SATISFIABLE.html
ErrorDocument 417 /X/err/4/HTTP_EXPECTATION_FAILED.html
ErrorDocument 422 /X/err/4/HTTP_UNPROCESSABLE_ENTITY.html
ErrorDocument 423 /X/err/4/HTTP_LOCKED.html
ErrorDocument 424 /X/err/4/HTTP_FAILED_DEPENDENCY.html
ErrorDocument 426 /X/err/4/HTTP_UPGRADE_REQUIRED.html
&nbsp;
ErrorDocument 500 /X/err/5/HTTP_INTERNAL_SERVER_ERROR.html
ErrorDocument 501 /X/err/5/HTTP_NOT_IMPLEMENTED.html
ErrorDocument 502 /X/err/5/HTTP_BAD_GATEWAY.html
ErrorDocument 503 /X/err/5/HTTP_SERVICE_UNAVAILABLE.html
ErrorDocument 504 /X/err/5/HTTP_GATEWAY_TIME_OUT.html
ErrorDocument 505 /X/err/5/HTTP_VERSION_NOT_SUPPORTED.html
ErrorDocument 506 /X/err/5/HTTP_VARIANT_ALSO_VARIES.html
ErrorDocument 507 /X/err/5/HTTP_INSUFFICIENT_STORAGE.html
ErrorDocument 510 /X/err/5/HTTP_NOT_EXTENDED.html
ErrorDocument 404 /index.php?error=404
&nbsp;
# 1 YEAR
&lt;filesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf)$"&gt;
Header unset P3P
Header set Cache-Control "public"
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/filesMatch&gt;
&nbsp;
# 2 HOURS
&lt;filesMatch "\.(html|htm|xml|txt|xsl)$"&gt;
&lt;ifModule mod_expires.c&gt;
ExpiresActive On
ExpiresDefault A3600
&lt;/ifModule&gt;
&lt;/filesMatch&gt;
&nbsp;
RewriteEngine On
RewriteBase /
&nbsp;
RewriteCond %{ENV:REDIRECT_STATUS} =200
RewriteRule .* - [L]
&nbsp;
RewriteCond %{REQUEST_METHOD} !^(GET|HEAD) [OR]
#RewriteCond %{QUERY_STRING} !^$ [OR]
RewriteCond %{HTTP_COOKIE} ^.*(comment_author_|wordpress|wp-postpass_).*$ [NC]
RewriteRule ^(.*)$ - [S=6]
&nbsp;
RewriteCond %{HTTP_USER_AGENT} .*W3C_Validator.* [NC]
RewriteCond %{HTTP:Accept-Encoding} gzip [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/aa/$1/index.xhtml.gz -f
RewriteRule ^(.*)$ /wp-content/cache/aa/$1/index.xhtml.gz [L,S=5]
&nbsp;
RewriteCond %{HTTP:Accept} application/xhtml\+xml [NC]
RewriteCond %{HTTP:Accept-Encoding} gzip [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/aa/$1/index.xhtml.gz -f
RewriteRule ^(.*)$ /wp-content/cache/aa/$1/index.xhtml.gz [L,S=4]
&nbsp;
RewriteCond %{HTTP:Accept-Encoding} gzip [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/aa/$1/index.html.gz -f
RewriteRule ^(.*)$ /wp-content/cache/aa/$1/index.html.gz [L,S=3]
&nbsp;
RewriteCond %{HTTP_USER_AGENT} .*W3C_Validator.* [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/aa/$1/index.xhtml -f
RewriteRule ^(.*)$ /wp-content/cache/aa/$1/index.xhtml [L,S=2]
&nbsp;
RewriteCond %{HTTP:Accept} application/xhtml\+xml [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/aa/$1/index.xhtml -f
RewriteRule ^(.*)$ /wp-content/cache/aa/$1/index.xhtml [L,S=1]
&nbsp;
RewriteCond %{DOCUMENT_ROOT}/wp-content/cache/aa/$1/index.html -f
RewriteRule ^(.*)$ /wp-content/cache/aa/$1/index.html [L]
&nbsp;
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(.+)\.rdf\ HTTP/ [NC]
RewriteCond %{DOCUMENT_ROOT}/wp-content/rdf/%1.html/index.rdf -f
RewriteRule ^(.*)$ /wp-content/rdf/%1.html/index.rdf [L,S=1]
&nbsp;
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(error|w3c|openid)(/?.*)\ HTTP/ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /X/%1%2 [L]
&nbsp;
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(y_key_bf61afd498f7623a\.html|google3bb7b7e1032ad0d4\.html|yadis\.xrdf|askapache-home\.rdf|os-description\.xml|labels\.rdf|gnu-fdl\.txt|wlmmanifest\.xml|robots\.txt)\ HTTP/ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* /X/%1 [L]
&nbsp;
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /X(.*)\ HTTP/ [NC]
RewriteRule .* - [F]
&nbsp;
RewriteRule ^osq?(.*)$ /wp-content/plugins/wp-opensearch.php?$1 [QSA,L]
&nbsp;
#RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /wp-login(.+)\ HTTP/ [NC]
#RewriteRule .+ https://www.askapache.com/wp-login%1 [R,L]
&nbsp;
RewriteCond %{REQUEST_URI} ^/cgi-bin/(hash|java)\.cgi$ [NC]
RewriteCond %{HTTP:P3P} ^(([^:]+):(.+))$ [NC]
RewriteRule .* - [E=HTTP_JS:%{HTTP:P3P},E=HTTP_US:%2,E=HTTP_PA:%3]
&nbsp;
RewriteCond %{HTTP_ACCEPT} application/xrds\+xml
RewriteCond %{HTTP_ACCEPT} !application/xrds\+xml\s*;\s*q\s*=\s*0(\.0{1,3})?\s*(,|$)
RewriteRule ^$ http://www.askapache.com/yadis.xrdf [R,L]
&nbsp;
RewriteCond %{HTTP_USER_AGENT} !^(FeedBurner|FeedValidator|talkr.com).* [NC]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(feed|rdf|rss|rss2|atom)/?.*\ HTTP/ [NC]
#RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /(feed|rdf|rss|rss2|atom|wp-atom|wp-feed|wp-rdf|wp-rss|wp-rss2).*\ HTTP/ [NC]
RewriteRule .* http://feeds.askapache.com/apache/htaccess? [R=302,L]
&nbsp;
#RewriteCond %{REMOTE_ADDR} ^$
#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
#RewriteRule ^(.+)\.phps$ /cgi-bin/phps.php?file=$1.php [L,NC]</pre>

<p><a href="http://www.askapache.com/htaccess/real-world-htaccess-files.html"></a><a href="http://www.askapache.com/htaccess/real-world-htaccess-files.html">Actual Htaccess Files from My Server</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/htaccess/real-world-htaccess-files.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>PHP5 Custom Install Shell Script Example</title>
		<link>http://www.askapache.com/shellscript/php5-custom-install.html</link>
		<comments>http://www.askapache.com/shellscript/php5-custom-install.html#comments</comments>
		<pubDate>Mon, 17 Dec 2007 04:11:31 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Shell Scripting]]></category>

		<guid isPermaLink="false">http://www.askapache.com/dreamhost/php5-custom-install.html</guid>
		<description><![CDATA[<p>Today I successfully learned how to <strong>compile and run multiple custom php</strong> installations for a DreamHost account, and to get it working I came upon a simple shell script that I made a couple changes to.</p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/shellscript/php5-custom-install.html"></a><a href="http://www.askapache.com/shellscript/php5-custom-install.html"><cite>AskApache.com</cite></a></p><p>Today I successfully learned how to <strong>compile and run multiple custom php</strong> installations for a DreamHost account, and to get it working I came upon a simple shell script that I made a couple changes to.</p>

<p>This script downloads the correct files, php extensions, and source code that you will need to get a custom php5 environment set up on DH.  Its a rather dangerous file though if you don't know what you are doing, because compiling your own custom php-cgi for your web sites isn't exactly a common thing.  This file will delete a couple of your directories if you aren't careful, I just posted it here because I enjoyed hacking this out and this is a pretty cool example of some of the <a href="http://static.askapache.com/shell-scripts/bash/">things you can do with the unix shell</a>.</p>

<p class="tlapost">Its fun to rotate between languages like that, although shell programming isn't exactly the most exciting thing compared to python, ruby, and other great <em>Object->Oriented</em> languages taking over.  But they do all run in the shell :)</p>


<blockquote cite="http://wiki.dreamhost.com/PHP_5_install_script">These are alternative PHP 5 install scripts created by Charles Wiltgen, who created them to work around problems he was having with the "main" PHP 5 install script.</blockquote>

<p>Discussed in more detail on the <a href="http://wiki.dreamhost.com/PHP_5_install_script">DreamHost Customer Wiki</a>.</p>


<h2>Functions in Shell Scripts</h2>
<p>Two changes I made were adding some <strong>functionality</strong> to the code with these two tiny gunctions, one downloads compressed files, the other decompresses them.</p>
<pre>function aa_unpack () {
  # compressed, tar and gzip files to DISTDIR
  if [ -f $DISTDIR/$1* ] ; then
    echo Extracting "$1";
    zcat ${DISTDIR}/$1* | tar -xvf - &amp;&gt;/dev/null;
    echo Done.;  echo; wait
  fi
}
&nbsp;
function askapache_grab () {
  #saves file to SRCDIR
    echo `basename $1`
  curl -L --retry 20 --max-time 1800 --retry-delay 30 -# -f --max-redirs 4 --remote-name "$1"
}</pre>




<h3>php5-install-prep.sh - Source Code</h3>
<pre>#!/bin/sh
&nbsp;
# Version 0.6, 2007-12-16
#
# - Updated 2007-12-16 by AskApache (www.askapache.com)
#   - Implemented functions to fetch the URI and decompress it
#   - Added a couple more error-checks
#   - Replaced wget with cURL
#   - Added more to help keep it from getting killed
#  - Updated to php-5.2.3, curl-7.17.1, freetype-2.3.5
# - Updated 2007-01-15 by Charles Wiltgen (charles@wiltgen.net)
#   - Make "nicer" to help keep it from getting killed by DreamHost
#   - Make less verbose to keep signal-to-noise level high
# - Updated 2006-12-25 by Carl McDade (hiveminds.co.uk)
#   - Allow memory limit and freetype
&nbsp;
# Abort on any errors
set -e
&nbsp;
# The domain in which to install the PHP CGI script.
export DOMAIN="askapache.com"
&nbsp;
# Where do you want all this stuff built? I&#039;d recommend picking a local filesystem.
# ***Don&#039;t pick a directory that already exists!***
SRCDIR=${HOME}/source
&nbsp;
# And where should it be installed?
INSTALLDIR=${HOME}/php5
&nbsp;
# Set DISTDIR to somewhere persistent, if you plan to muck around with this
# script and run it several times!
DISTDIR=${HOME}/dist
&nbsp;
# Update version information here.
PHP5="php-5.2.3"
LIBICONV="libiconv-1.11"
LIBMCRYPT="libmcrypt-2.5.7"
LIBXML2="libxml2-2.6.27"
LIBXSLT="libxslt-1.1.18"
MHASH="mhash-0.9.7.1"
ZLIB="zlib-1.2.3"
CURL="curl-7.17.1"
LIBIDN="libidn-0.6.8"
CCLIENT="imap-2004g"
CCLIENT_DIR="imap-2004g"
FREETYPE="freetype-2.3.5"
&nbsp;
# Push the install dir&#039;s bin directory into the path
export PATH=${INSTALLDIR}/bin:$PATH
&nbsp;
function aa_unpack () {
  # compressed, tar and gzip files to DISTDIR
  if [ -f $DISTDIR/$1* ] ; then
    echo Extracting "$1";
    zcat ${DISTDIR}/$1* | tar -xvf - &amp;&gt;/dev/null;
    echo Done.;  echo; wait
  fi
}
&nbsp;
function askapache_grab () {
  #saves file to SRCDIR
    echo `basename $1`
  curl -L --retry 20 --max-time 1800 --retry-delay 30 -# -f --max-redirs 4 --remote-name "$1"
}
&nbsp;
echo
echo --------------------------------------------------
echo --   Run this script before php5-install.sh     --
echo --------------------------------------------------
echo
echo - Downloads and unpacks all prerequisite packages
echo - **SRCDIR and DISTDIR will be deleted**
echo
read -p  "        (Press any key to continue)" temp;
echo;echo
&nbsp;
# cleanup to remove source and dist directories if present
if [ -d "$SRCDIR" ] || [ -d "$DISTDIR" ];then
  echo
  echo --- Cleaning up any previous attempts ---
  rm -rf $SRCDIR $DISTDIR &amp;&gt;/dev/null
  echo Done.
  echo
  wait
fi
&nbsp;
#setup directories
mkdir -p ${SRCDIR} ${INSTALLDIR} ${DISTDIR} &amp;&gt;/dev/null
&nbsp;
# Get all the required packages
echo;echo
echo --- Downloading all required packages ---
echo
&nbsp;
cd ${DISTDIR}
askapache_grab http://us.php.net/distributions/${PHP5}.tar.gz
askapache_grab http://mirrors.usc.edu/pub/gnu/libiconv/${LIBICONV}.tar.gz
askapache_grab http://umn.dl.sourceforge.net/sourceforge/mcrypt/${LIBMCRYPT}.tar.gz
askapache_grab ftp://xmlsoft.org/libxml2/${LIBXML2}.tar.gz
askapache_grab ftp://xmlsoft.org/libxml2/${LIBXSLT}.tar.gz
askapache_grab http://umn.dl.sourceforge.net/sourceforge/mhash/${MHASH}.tar.gz
askapache_grab http://www.zlib.net/${ZLIB}.tar.gz
askapache_grab http://curl.askapache.com/download/${CURL}.tar.gz
askapache_grab http://easynews.dl.sourceforge.net/sourceforge/freetype/${FREETYPE}.tar.gz
askapache_grab ftp://alpha.gnu.org/pub/gnu/libidn/${LIBIDN}.tar.gz
askapache_grab ftp://ftp.cac.washington.edu/imap/old/${CCLIENT}.tar.Z
wait
echo Done.
&nbsp;
# Extract the files from the required packages.
echo;echo;echo
echo --- Unpacking downloaded archives. This process may take several minutes! ---
echo
&nbsp;
cd ${SRCDIR}
aa_unpack ${PHP5}
aa_unpack ${LIBICONV}
aa_unpack ${LIBMCRYPT}
aa_unpack ${LIBXML2}
aa_unpack ${LIBXSLT}
aa_unpack ${MHASH}
aa_unpack ${ZLIB}
aa_unpack ${CURL}
aa_unpack ${LIBIDN}
aa_unpack ${CCLIENT}
aa_unpack ${FREETYPE}
wait
&nbsp;
echo --------------------------------------------------
echo -- Done downloading and unpacking prerequisites --
echo --------------------------------------------------
&nbsp;
exit 0;</pre>



<h3>php5-install-prep.sh - Output</h3>
<pre>[root@~/.^*][~/dm/e]
$ ./php5-install-prep.sh
&nbsp;
--------------------------------------------------
-- Run this script before php5-install.sh --
--------------------------------------------------
&nbsp;
- Downloads and unpacks all prerequisite packages
- **SRCDIR and DISTDIR will be deleted**
&nbsp;
        (Press any key to continue)
&nbsp;
--- Cleaning up any previous attempts ---
Done.
&nbsp;
--- Downloading all required packages ---
&nbsp;
php-5.2.3.tar.gz
######################################################################## 100.0%
libiconv-1.11.tar.gz
######################################################################## 100.0%
libmcrypt-2.5.7.tar.gz
######################################################################## 100.0%
libxml2-2.6.27.tar.gz
######################################################################## 100.0%
libxslt-1.1.18.tar.gz
######################################################################## 100.0%
mhash-0.9.7.1.tar.gz
######################################################################## 100.0%
zlib-1.2.3.tar.gz
######################################################################## 100.0%
curl-7.17.1.tar.gz
######################################################################## 100.0%
freetype-2.3.5.tar.gz
######################################################################## 100.0%
libidn-0.6.8.tar.gz
######################################################################## 100.0%
imap-2004g.tar.Z
######################################################################## 100.0%
Done.
&nbsp;
--- Unpacking downloaded archives. This process may take several minutes! ---
&nbsp;
Extracting php-5.2.3
Done.
&nbsp;
Extracting libiconv-1.11
Done.
&nbsp;
Extracting libmcrypt-2.5.7
Done.
&nbsp;
Extracting libxml2-2.6.27
Done.
&nbsp;
Extracting libxslt-1.1.18
Done.
&nbsp;
Extracting mhash-0.9.7.1
Done.
&nbsp;
Extracting zlib-1.2.3
Done.
&nbsp;
Extracting curl-7.17.1
Done.
&nbsp;
Extracting libidn-0.6.8
Done.
&nbsp;
Extracting imap-2004g
Done.
&nbsp;
Extracting freetype-2.3.5
Done.
&nbsp;
--------------------------------------------------
-- Done downloading and unpacking prerequisites --
--------------------------------------------------</pre><p><a href="http://www.askapache.com/shellscript/php5-custom-install.html"></a><a href="http://www.askapache.com/shellscript/php5-custom-install.html">PHP5 Custom Install Shell Script Example</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/shellscript/php5-custom-install.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Awk Tutorial and Introduction</title>
		<link>http://www.askapache.com/linux/awk-tutorial.html</link>
		<comments>http://www.askapache.com/linux/awk-tutorial.html#comments</comments>
		<pubDate>Mon, 12 Nov 2007 18:20:46 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Linux]]></category>

		<guid isPermaLink="false">http://www.askapache.com/awk/awk-tutorial.html</guid>
		<description><![CDATA[<p>While researching a unix/linux tool <code>awk</code> I came upon one of the most thorough and helpful tutorials I've ever seen devoted to a particular topic.  It's old-school just the way I like it.  I contacted the author, <a href="http://www.grymoire.com/">Bruce Barnett</a> because I just HAD to have this article for my readers, who are predominantly running solaris/unix/bsd/linux and he kindly gave permission.</p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/linux/awk-tutorial.html"></a><a href="http://www.askapache.com/linux/awk-tutorial.html"><cite>AskApache.com</cite></a></p><p>While researching a unix/linux tool <code>awk</code> I came upon one of the most thorough and helpful tutorials I've ever seen devoted to a particular topic.  It's old-school just the way I like it.  I contacted the author, <a href="http://www.grymoire.com/">Bruce Barnett</a> because I just HAD to have this article for my readers, who are predominantly running solaris/unix/bsd/linux and he kindly gave permission.  So, without further ado, I present: <a href="http://www.grymoire.com/Unix/Awk.html">Awk - A Tutorial and Introduction - by Bruce Barnett</a></p>
<hr class="C" />
<p class="cnote">Copyright 2001,2004 Bruce Barnett and General Electric Company
    All rights reserved.
    You are allowed to print copies of this tutorial for your personal use, and link to this page, but you are not allowed to make electronic copies, or redistribute this tutorial in any form without permission.
    Last update: Tue Mar  9 11:07:08 EST 2004</p>
<p>Awk is an extremely versatile programming language for working on files. We'll teach you just enough to understand the examples in this book, plus a smidgen.</p>





<h2>Table of Contents</h2>
<ul>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-0" name="toc-awk-0" id="toc-awk-0">Why learn AWK?</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-1" name="toc-awk-1" id="toc-awk-1">Basic Structure</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-2" name="toc-awk-2" id="toc-awk-2">Executing an AWK script</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-3" name="toc-awk-3" id="toc-awk-3">Which shell to use with AWK?</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-4" name="toc-awk-4" id="toc-awk-4">Dynamic Variables</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-5" name="toc-awk-5" id="toc-awk-5">The Essential Syntax of AWK</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-6" name="toc-awk-6" id="toc-awk-6">Arithmetic Expressions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-7" name="toc-awk-7" id="toc-awk-7">Unary arithmetic operators</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-8" name="toc-awk-8" id="toc-awk-8">The Autoincrement and Autodecrement Operators</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-9" name="toc-awk-9" id="toc-awk-9">Assignment Operators</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-10" name="toc-awk-10" id="toc-awk-10">Conditional expressions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-11" name="toc-awk-11" id="toc-awk-11">Regular Expressions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-12" name="toc-awk-12" id="toc-awk-12">And/Or/Not</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-13" name="toc-awk-13" id="toc-awk-13">Commands</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-14" name="toc-awk-14" id="toc-awk-14">AWK Built-in Variables</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-15" name="toc-awk-15" id="toc-awk-15">FS - The Input Field Separator Variable</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-16" name="toc-awk-16" id="toc-awk-16">OFS - The Output Field Separator Variable</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-17" name="toc-awk-17" id="toc-awk-17">NF - The Number of Fields Variable</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-18" name="toc-awk-18" id="toc-awk-18">NR - The Number of Records Variable</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-19" name="toc-awk-19" id="toc-awk-19">RS - The Record Separator Variable</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-20" name="toc-awk-20" id="toc-awk-20">ORS - The Record Separator Variable</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-21" name="toc-awk-21" id="toc-awk-21">FILENAME - The Current Filename Variable"</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-22" name="toc-awk-22" id="toc-awk-22">Associative Arrays</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-23" name="toc-awk-23" id="toc-awk-23">Multi-dimensional Arrays</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-24" name="toc-awk-24" id="toc-awk-24">Example of using AWK's Associative Arrays</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-25" name="toc-awk-25" id="toc-awk-25">Output of the script</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-26" name="toc-awk-26" id="toc-awk-26">Picture Perfect PRINTF Output</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-27" name="toc-awk-27" id="toc-awk-27">PRINTF - formatting output</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-28" name="toc-awk-28" id="toc-awk-28">Escape Sequences</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-29" name="toc-awk-29" id="toc-awk-29">Format Specifiers</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-30" name="toc-awk-30" id="toc-awk-30">Width - specifying minimum field size</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-31" name="toc-awk-31" id="toc-awk-31">Left Justification</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-32" name="toc-awk-32" id="toc-awk-32">The Field Precision Value</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-33" name="toc-awk-33" id="toc-awk-33">Explicit File output</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-34" name="toc-awk-34" id="toc-awk-34">AWK Numerical Functions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-35" name="toc-awk-35" id="toc-awk-35">Trigonometric Functions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-36" name="toc-awk-36" id="toc-awk-36">Exponents, logs and square roots</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-37" name="toc-awk-37" id="toc-awk-37">Truncating Integers</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-38" name="toc-awk-38" id="toc-awk-38">"Random Numbers</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-39" name="toc-awk-39" id="toc-awk-39">The Lotto script</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-40" name="toc-awk-40" id="toc-awk-40">String Functions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-41" name="toc-awk-41" id="toc-awk-41">The Length function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-42" name="toc-awk-42" id="toc-awk-42">The Index Function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-43" name="toc-awk-43" id="toc-awk-43">The Substr function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-44" name="toc-awk-44" id="toc-awk-44">GAWK's Tolower and Toupper function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-45" name="toc-awk-45" id="toc-awk-45">The Split function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-46" name="toc-awk-46" id="toc-awk-46">NAWK's string functions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-47" name="toc-awk-47" id="toc-awk-47">The Match function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-48" name="toc-awk-48" id="toc-awk-48">The System function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-49" name="toc-awk-49" id="toc-awk-49">The Getline function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-50" name="toc-awk-50" id="toc-awk-50">The systime function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-51" name="toc-awk-51" id="toc-awk-51">The Strftime function</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-52" name="toc-awk-52" id="toc-awk-52">User Defined Functions</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-53" name="toc-awk-53" id="toc-awk-53">AWK patterns</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-54" name="toc-awk-54" id="toc-awk-54">Formatting AWK programs</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-55" name="toc-awk-55" id="toc-awk-55">Environment Variables</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-56" name="toc-awk-56" id="toc-awk-56">ARGC - Number or arguments (NAWK/GAWK)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-57" name="toc-awk-57" id="toc-awk-57">ARGV - Array of arguments (NAWK/GAWK)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-58" name="toc-awk-58" id="toc-awk-58">ARGIND - Argument Index (GAWK only)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-59" name="toc-awk-59" id="toc-awk-59">FNR (NAWK/GAWK)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-60" name="toc-awk-60" id="toc-awk-60">OFMT (NAWK/GAWK)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-61" name="toc-awk-61" id="toc-awk-61">RSTART, RLENGTH and match (NAWK/GAWK)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-62" name="toc-awk-62" id="toc-awk-62">SUBSEP - Multi-dimensional array separator (NAWK/GAWK)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-63" name="toc-awk-63" id="toc-awk-63">ENVIRON - environment variables (GAWK only)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-64" name="toc-awk-64" id="toc-awk-64">IGNORECASE (GAWK only)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-65" name="toc-awk-65" id="toc-awk-65">CONVFMT - conversion format (GAWK only)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-66" name="toc-awk-66" id="toc-awk-66">ERRNO - system errors (GAWK only)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-67" name="toc-awk-67" id="toc-awk-67">FIELDWIDTHS - fixed width fields (GAWK only)</a></li>
    <li><a href="http://www.askapache.com/awk/awk-tutorial.html#awk-68" name="toc-awk-68" id="toc-awk-68">AWK, NAWK, GAWK, or PERL</a></li>
</ul>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-0" name="awk-0" id="awk-0" title="Why learn AWK?">Why learn AWK?</a></h2>
<p>In the past I have covered <em>grep</em> and <em>sed</em>. This section discusses AWK, another cornerstone of UNIX shell programming. There are three variations of AWK:</p>
<pre>AWK - the original from AT&amp;amp;T
NAWK - A newer, improved version from AT&amp;amp;T
GAWK - The Free Software foundation&#039;s version</pre>
<p>Originally, I didn't plan to discuss NAWK, but several UNIX vendors have replaced AWK with NAWK, and there are several incompatibilities between the two. It would be cruel of me to not warn you about the differences. So I will highlight those when I come to them. It is important to know than all of AWK's features are in NAWK and GAWK. Most, if not all, of NAWK's features are in GAWK. NAWK ships as part of Solaris. GAWK does not. However, many sites on the Internet have the sources freely available. If you user Linux, you have GAWK.</p>
<p>Why is AWK so important? It is an excellent filter and report writer. Many UNIX utilities generates rows and columns of information. AWK is an excellent tool for processing these rows and columns, and is easier to use AWK than most conventional programming languages. It can be considered to be a pseudo-C interpretor, as it understands the same arithmatic operators as C. AWK also has string manipulation functions, so it can search for particular strings and modify the output. AWK also has associative arrays, which are incredible useful, and is a feature most computing languages lack. Associative arrays can make a complex problem a trivial exercise.</p>
<p>I won't exhaustively cover AWK.  That is, I will cover the essential parts, and avoid the many variants of AWK. It might be too confusing to discuss three different versions of AWK. I won't cover the GNU version of AWK called "gawk." Similarly, I will not discuss the new AT&amp;T AWK called "nawk." The new AWK comes on the Sun system, and you may find it  superior to the old AWK in many ways. In particular, it has better diagnostics, and won't print out the infamous  "bailing out near line ..." message the original AWK is prone to do. Instead,  "nawk" prints out the line it didn't understand,  and highlights the bad parts with arrows. If you find yourself needing a feature that is very difficult or impossible  to do in AWK, I suggest you either use NAWK, or convert your AWK script into  PERL using the "a2p" conversion program which comes with PERL.  PERL is a marvelous language, and I use it all the time, but I do not plan to cover PERL in these tutorials. Having made my intention clear, I can continue with a clear conscience.</p>
<p>Many UNIX utilities have strange names. AWK is one of those utilities. It is not an abbreviation for <em>awk</em>ward. In fact, it is an elegant and simple language. The work "AWK" is derived from the initials of the language's three developers: A. Aho,  B. W. Kernighan and P. Weinberger.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-1" name="awk-1" id="awk-1" title="Basic Structure">Basic Structure</a></h2>
<p>The essential organization of an AWK program follows the form:</p>
<pre>pattern { action }</pre>
<p>The pattern specifies when the action is performed. Like most UNIX utilities, AWK is line oriented. That is, the pattern specifies a test that is performed with each line read as input. If the condition is true, then the action is taken. The default pattern is something that matches every line. This is the blank or null pattern. Two other important patterns are specified by the keywords "BEGIN" and "END." As you might expect, these two words specify actions to be taken before any lines are read, and after the last line is read. The AWK program below:</p>
<pre>BEGIN   { print "START" }
{ print }
END     { print "STOP" }</pre>
<p>adds one line before and one line after the input file. This isn't very useful, but with a simple change, we can make this into a typical AWK program:</p>
<pre>BEGIN   { print "File  Owner"," }
 { print $8, "  ", $3}
END     { print " - DONE -" }</pre>
<p>The characters "<code>\t</code>" Indicates a tab character so the output lines up on even boundries. The "$8" and "$3" have a meaning similar to a shell script. Instead of the eighth and third argument, they mean the eighth and third field of the input line. You can think of a field as a column, and the action you specify operates on each line or row read in.</p>
<p>There are two differences between AWK and a shell processing the characters within double quotes. AWK understands special characters follow the "" character. The UNIX shells do not. Also, unlike the shell (and PERL) AWK does not evaluate variables within  strings. The second line could not be written like this:</p>
<pre>{print "$8  $3" }</pre>
<p>That example would print "$8 $3." Inside the quotes, the dollar sign is not a special character. Outside, it corresponds to a field. What do I mean by the third and eight field? Consider the "/usr/bin/ls -l" command, which  has eight columns of information. The System V version,  "/usr/5bin/ls -l," has 9 columns. The third column is the owner, and the eighth column in the name of the file. This AWK program can be used to process the output of the "ls -l" command, printing out the filename, then the owner, for each file. I'll show you how.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-2" name="awk-2" id="awk-2" title="Executing an AWK script">Executing an AWK script</a></h2>
<p>Assuming the script is called  "FileOwner," the invocation would be</p>
<pre>ls -l | FileOwner</pre>
<p>This might generate the following if there were only two files in the current directory:</p>
<pre>File  Owner
 a.file  barnett
 another.file    barnett
 - DONE -</pre>
<p>There are two problems with this script. Both problems are easy to fix, but I'll hold off on this until I cover the basics.</p>
<p>The script itself can be written in many ways. The C shell version would look like this: </p>
<pre>#!/bin/csh -f
awk &#039;
BEGIN   { print "File\tOwner" } \
{ print $8, "\t", $3}  \
END     { print " - DONE -" } \
&#039;</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example1.csh">awk_example1.csh</a></p>
<p>As you can see in the above script, each line of the AWK script must  have a backslash if it is not the last line of the script. This is necessary as the C shell doesn't, by default, allow strings to span more than one line. The Bourne shell allows quoted strings to span several lines:
<pre>#!/bin/sh
 awk &#039;
 BEGIN   { print "File\tOwner" }
 { print $8, "\t", $3}
 END     { print " - DONE -" }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example1.sh">awk_example1.sh</a> The third form is to store the commands in a file, and execute</p>
<pre>awk -f filename</pre>
<p>Since AWK is also an interpretor, you can make the file executable by add one line in the beginning of the file:</p>
<pre>#!/bin/awk -f
 BEGIN   { print "File\tOwner" }
 { print $8, "\t", $3}
 END     { print " - DONE -" }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example1.awk">awk_example1.awk</a></p>
<p>Change the permission with the <em>chmod</em> command, and the script becomes a new command. Notice the  "-f" option of AWK above, which is also used in the third format. It specifies the file containing the instructions. As you can see, AWK considers lines that start with a "#" to be a comment. Well, anything from the "#" to the end of the line is a comment.  However, I always comment my AWK scripts with the "#" at the start of the line, for reasons I'll discuss later.</p>
<p>Which format should you use? I prefer the last format when possible. It's shorter and simpler. It's also easier to debug problems. If you need to use a shell, and want to avoid using too many files, you can  combine them as we did in the first and second example.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-3" name="awk-3" id="awk-3" title="Which shell to use with AWK?">Which shell to use with AWK?</a></h2>
<p>The format of AWK is not free-form.  You cannot put new line breaks just anywhere. They must go in particular locations. To be precise, in the original AWK you can insert a new line character after the curly braces, and at the end of a command, but not elsewhere. If you wanted to break a long line into two lines at any other place,  you must use a backslash:</p>
<pre>#!/bin/awk -f
 BEGIN   { print "File\tOwner" }
 { print $8, "\t",
 $3}
 END     { print " - DONE -" }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example2.awk">awk_example2.awk</a></p>
<p>The Bourne shell version would be</p>
<pre>#!/bin/sh
 awk &#039;
 BEGIN  { print "File\tOwner" }
 { print $8, "\t",
 $3}
 END    { print "done"}
 &#039;</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example2.sh">awk_example2.sh</a></p>
<p>while the C shell would be</p>
<pre>#!/bin/csh -f
 awk &#039;
 BEGIN  { print "File\tOwner" }\
 { print $8, "\t", \\
 $3}\
 END    { print "done"}\
 &#039;</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example2.csh">awk_example2.csh</a></p>
<p>As you can see, this demonstrates how awkward the C shell is when enclosing an AWK script. Not only are back slashes needed for every line, some lines need two. (Note - this is true when using old awk (e.g. on Solaris) because the print statement had to be on one line. Newer AWK's allow the print statement to be on multiple lines.) Many people will warn you about the C shell. Some of the problems are subtle, and you may never see them. Try to include an AWK or <em>sed</em> script within a C shell script, and the back slashes will drive you crazy. This is what convinced me to learn the Bourne shell years ago, when I was starting out. I strongly recommend you use the Bourne shell for  any AWK or <em>sed</em> script. If you don't use the Bourne shell, then you should learn it.  As a minimum, learn how to set variables, which by some strange coincidence is the subject of the next section.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-4" name="awk-4" id="awk-4" title="Dynamic Variables">Dynamic Variables</a></h2>
<p>Since you can make a script an AWK executable by mentioning "#!/bin/awk -f" on the first line, including an AWK script inside a shell script isn't needed unless you want to either eliminate the need for an extra file,  or if you want to pass a variable to the insides of an AWK script. Since this is a common problem, now is as good a time to explain the technique. I'll do this by showing a simple AWK program that will only print one column. The number of the column will be specified by the first argument. The first version of the program, which we will call "Column," looks like this:
<pre>#!/bin/sh
 column=$1
 awk &#039;{print $column}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/Column1.sh">Column1.sh</a></p>
<p>A suggested use is:</p>
<pre>ls -l | Column 3</pre>
<p>This would print the third column from the <em>ls</em> command, which would be the owner of the file. You can change this into a utility that  counts how many files are owned by each user by adding</p>
<pre>ls -l | Column 3 | uniq -c | sort -nr</pre>
<p>Only one problem: the script doesn't work. The value of the "column" variable is not seen by AWK. Change "awk" to "echo" to check. You need to turn off the quoting when the variable is seen. This can be done by  ending the quoting, and restarting it after the variable:
<pre>#!/bin/sh
 column=$1
 awk &#039;{print $&#039;$column&#039;}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/Column2.sh">Column2.sh</a></p>
<p>This is a very important concept, and throws experienced programmers a curve ball. In many computer languages, a string has a start quote, and end quote,  and the contents in between. If you want to include a special character inside the quote, you must  prevent the character from having the typical meaning.  In C this is down by putting a backslash before the character. In other languages, there is a special combination of characters to to this. In the C and Bourne shell, the quote is just a switch. It turns the interpretation mode on or off. There is really no such concept as  "start of string" and "end of string." The quotes toggle a switch inside the interpretor. The quote character is not passed on to the application. This is why there are two pairs of quotes above. Notice there are two dollar signs. The first one is quoted, and is seen by AWK. The second one is not quoted, so the shell evaluates the variable, and replaces "$column" by the value. If you don't understand, either change "awk" to "echo," or change the first line to read "#!/bin/sh -x."</p>
<p>Some improvements are needed, however. The Bourne shell has a mechanism to provide a value for a variable if the value isn't set, or is set and the value is an empty string. This is done by using the format:</p>
<pre>${variable:-defaultvalue}</pre>
<p>This is shown below, where the default column will be one:
<pre>#!/bin/sh
 column=${1:-1}
 awk &#039;{print $&#039;$column&#039;}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/Column3.sh">Column3.sh</a></p>
<p>We can save a line by combining these two steps:
<pre>#!/bin/sh
 awk &#039;{print $&#039;${1:-1}&#039;}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/Column4.sh">Column4.sh</a></p>
<p>It is hard to read, but it is compact. There is one other method that can be used. If you execute an AWK command and include on the command line</p>
<pre>variable=value</pre>
<p>this variable will be set when the AWK script starts. An example of this use would be:
<pre>#!/bin/sh
 awk &#039;{print $c}&#039; c=${1:-1}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/Column5.sh">Column5.sh</a></p>
<p>This last variation does not have the problems with  quoting the previous example had. You should master the earlier example, however, because you can use it with any script or command. The second method is special to AWK.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-5" name="awk-5" id="awk-5" title="The Essential Syntax of AWK">The Essential Syntax of AWK</a></h2>
<p>Earlier I discussed ways to start an AWK script. This section will discuss the various grammatical elements of AWK.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-6" name="awk-6" id="awk-6" title="Arithmetic Expressions">Arithmetic Expressions</a></h2>
<p>There are several arithmetic operators, similar to C. These are the binary  operators,  which operate on two variables:</p>
<pre>+--------------------------------------------+
|    AWK Table 1        |
|       Binary Operators        |
|Operator  Type       Meaning      |
+--------------------------------------------+
|+    Arithmetic   Addition      |
|-    Arithmetic   Subtraction    |
|*    Arithmetic   Multiplication |
|/    Arithmetic   Division      |
|%    Arithmetic   Modulo      |
|&lt;space&gt;  String       Concatenation      |
+--------------------------------------------+</pre>
<p> Using variables with the value of  "7" and "3," AWK returns the following results for each operator when using the print command:</p>
<pre>+---------------------+
|Expression   Result   |
+---------------------+
  |7+3     10   |
   |7-3     4   |
  |7*3     21   |
|7/3     2.33333 |
   |7%3     1   |
  |7 3     73   |
+---------------------+</pre>
<p>There are  a few points to make. The modulus operator finds the remainder after an integer divide.  The <em>print</em> command output a floating point number on the divide, but an integer for the rest.  The string concatenate operator is confusing, since it isn't even visible.  Place a space between two variables and the strings are concatenated together. This also shows that numbers are converted automatically into strings  when needed. Unlike C, AWK doesn't have  "types" of variables. There is one type only, and it can be a string or number.  The conversion rules are simple. A number can easily be converted into a string.  When a string is converted into a number, AWK will do so. The string "123" will be converted into the number 123. However, the string "123X" will be converted into the number 0. (NAWK will behave differently, and converts the string into integer 123, which is found in the beginning of the string).</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-7" name="awk-7" id="awk-7" title="Unary arithmetic operators">Unary arithmetic operators</a></h2>
<p>The "+" and "-" operators can be used before variables and numbers. If X equals 4, then the statement:</p>
<pre>print -x;</pre>
<p>will print </p>
<pre>"-4."</pre>




<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-8" name="awk-8" id="awk-8" title="The Autoincrement and Autodecrement Operators">The Autoincrement and Autodecrement Operators</a></h2>
<p>AWK also supports the "++" and "--" operators of C. Both increment or decrement the variables by one.  The operator can only be used with a single variable, and can be before or after the variable.  The prefix form modifies the value, and then uses the result, while the postfix form gets the results of the variable, and afterwards modifies the variable.  As an example, if X has the value of 3, then the AWK statement</p>
<pre>print x++, " ", ++x;</pre>
<p>would print the numbers 3 and 5. These operators are also assignment operators, and can be used by themselves on a line:</p>
<pre>x++;
--y;</pre>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-9" name="awk-9" id="awk-9" title="Assignment Operators">Assignment Operators</a></h2>
<p>Variables can be assigned new values with the assignment operators. You know about "++" and "--." The other assignment statement is simply:</p>
<pre>variable = arithmetic_expression</pre>
<p>Certain operators have precedence over others; parenthesis can be used to control grouping. The statement</p>
<pre>x=1+2*3 4;</pre>
<p>is the same as</p>
<pre>x = (1 + (2 * 3))  "4";</pre>
<p>Both print out  "74."</p>
<p>Notice spaces can be added for readability. AWK, like C, has special assignment operators, which combine a calculation with an assignment. Instead of saying</p>
<pre>x=x+2;</pre>
<p>you can more concisely say:</p>
<pre>x+=2;</pre>
<p>The complete list follows:</p>
<pre>+-----------------------------------------+
|    AWK Table 2       |
|      Assignment Operators     |
|Operator   Meaning         |
|+=       Add result to variable     |
|-=       Subtract result from variable |
|*=       Multiply variable by result   |
|/=       Divide variable by result     |
|%=       Apply modulo to variable     |
+-----------------------------------------+</pre>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-10" name="awk-10" id="awk-10" title="Conditional expressions">Conditional expressions</a></h2>
<p>The second type of expression in AWK is the conditional expression. This is used for certain tests, like the <em>if</em> or <em>while</em>. Boolean conditions evaluate to true or false.  In AWK, there is a definite difference between a boolean condition, and an arithmetic expression.  You cannot convert a boolean condition to an integer or string.  You can, however, use an arithmetic expression as a conditional expression. A value of 0 is false, while anything else is true. Undefined variables has the value of 0. Unlike AWK, NAWK lets you use booleans as integers.</p>
<p>Arithmetic values can also be converted into boolean conditions by using relational operators:</p>
<pre>+---------------------------------------+
|    AWK Table 3      |
|      Relational Operators    |
|Operator   Meaning        |
+---------------------------------------+
|==        Is equal        |
|!=        Is not equal to      |
|&gt;        Is greater than      |
|&gt;=      Is greater than or equal to |
|&lt;        Is less than      |
|&lt;=      Is less than or equal to    |
&nbsp;
+---------------------------------------+</pre>
<p>These operators are the same as the C operators. They can be used to compare numbers or strings. With respect to strings, lower case letters are greater than upper case letters.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-11" name="awk-11" id="awk-11" title="Regular Expressions">Regular Expressions</a></h2>
<p>Two operators are used to compare strings to regular expressions:</p>
<pre>+-----------------------------+
|  AWK Table 4       |
|Regular Expression Operators |
|Operator     Meaning       |
+-----------------------------+
|~       Matches       |
|!~       Doesn&#039;t match   |
+-----------------------------+</pre>
<p>The order in this case is particular. The regular expression must be enclosed by slashes, and comes after the operator.  AWK supports extended regular expressions, so the following are examples of valid tests:</p>
<pre>word !~ /START/
lawrence_welk ~ /(one|two|three)/</pre>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-12" name="awk-12" id="awk-12" title="And/Or/Not">And/Or/Not</a></h2>
<p>There are two boolean operators that can be used with conditional expressions. That is, you can combine two conditional expressions with the "or" or "and" operators: "&amp;&amp;" and "||." There is also the unary not operator: "!."</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-13" name="awk-13" id="awk-13" title="Commands">Commands</a></h2>
<p>There are only a few commands in AWK. The list and syntax follows:</p>
<pre>if ( conditional ) statement [ else statement ]
 while ( conditional ) statement
 for ( expression ; conditional ; expression ) statement
 for ( variable in array ) statement
 break
 continue
 { [ statement ] ...}
 variable=expression
 print [ expression-list ] [ &gt; expression ]
 printf format [ , expression-list ] [ &gt; expression ]
 next
 exit</pre>
<p>At this point, you can use AWK as a language for simple calculations; If you wanted to calculate something, and not read any lines for input, you could use the BEGIN keyword discussed earlier, combined with a exit command:</p>
<pre>#!/bin/awk -f
BEGIN {
&nbsp;
# Print the squares from 1 to 10 the first way
&nbsp;
i=1;
while (i &lt;= 10) {
printf "The square of ", i, " is ", i*i;
i = i+1;
}
&nbsp;
# do it again, using more concise code
&nbsp;
for (i=1; i &lt;= 10; i++) {
printf "The square of ", i, " is ", i*i;
}
&nbsp;
# now end
exit;
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_print_squares.awk">awk_print_squares.awk</a> The following asks for a number, and then squares it:</p>
<pre>#!/bin/awk -f
BEGIN {
print "type a number";
}
{
print "The square of ", $1, " is ", $1*$1;
print "type another number";
}
END {
print "Done"
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_ask_for_square.awk">awk_ask_for_square.awk</a></p>
<p>The above isn't a good filter, because it asks for input each time. If you pipe the output of another program into it, you would generate a lot of meaningless prompts.</p>
<p>Here is a filter that you should find useful. It counts lines, totals up the numbers in the first column, and calculates the average. Pipe "wc -c *" into it, and it will count files, and tell you the average number of words per file, as well as the total words and the number of files.</p>
<pre>#!/bin/awk -f
BEGIN {
# How many lines
lines=0;
total=0;
}
{
# this code is executed once for each line
# increase the number of files
lines++;
# increase the total size, which is field #1
total+=$1;
}
END {
# end, now output the total
print lines " lines read";
print "total is ", total;
if (lines &gt; 0 ) {
print "average is ", total/lines;
} else {
print "average is 0";
}
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/average.awk">average.awk</a></p>
<p>You can pipe the output of  "ls -s" into this filter to count the number of files, the total size, and the average size. There is a slight problem with this script, as it includes the output of  "ls" that reports the total.  This causes the number of files to be off by one. Changing</p>
<pre>lines++;</pre>
<p>to</p>
<pre>if ($1 != "total" ) lines++;</pre>
<p>will fix this problem. Note the code which prevents a divide by zero. This is common in well-written scripts.  I also initialize the variables to zero. This is not necessary, but it is a good habit.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-14" name="awk-14" id="awk-14" title="AWK Built-in Variables">AWK Built-in Variables</a></h2>
<p>I have mentioned two kinds of variables: positional and user defined. A user defined variable is one you create. A positional variable is not a special variable, but a function triggered by the dollar sign. Therefore</p>
<pre> print $1;</pre>
<p>and</p>
<pre> X=1;
 print $X;</pre>
<p>do the same thing: print the first field on the line. There are two more points about positional variables that are very useful. The variable "$0" refers to the entire line that AWK reads in. That is, if you had eight fields in a line,</p>
<pre> print $0;</pre>
<p>is similar to</p>
<pre> print $1, $2, $3, $4, $5, $6, $7, $8</pre>
<p>This will change the spacing between the fields; otherwise, they behave the same. You can modify positional variables. The following commands</p>
<pre> $2="";
 print;</pre>
<p>deletes the second field. If you had four fields, and wanted to print out the second and fourth field, there are two ways. This is the first:</p>
<pre>#!/bin/awk -f
 {
 $1="";
 $3="";
 print;
 }</pre>
<p>and the second</p>
<dl>
    <dd>
        <p> #!/bin/awk -f
            {
            print $2, $4;
            }</p>
    </dd>
</dl>
<p>These perform similarly, but not identically. The number of spaces between the values vary. There are two reasons for this. The actual number of fields does not change. Setting a positional variable to an empty string does not delete the variable. It's still there, but the contents has been deleted. The other reason is the way AWK outputs the entire line. There is a field separator that specifies what character  to put between the fields on output. The first example outputs four fields, while the second outputs two. In-between each field is a space. This is easier to explain if the characters between fields could be modified to be made more visible.  Well, it can. AWK provides special variables for just that purpose.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-15" name="awk-15" id="awk-15" title="FS - The Input Field Separator Variable">FS - The Input Field Separator Variable</a></h2>
<p>AWK can be used to parse many system administration files. However, many of these files do not have whitespace as a separator. as an example, the password file uses colons. You can easily change the field separator character to be a colon using the  "-F" command line option.  The following command will print out accounts that don't have passwords:</p>
<pre>awk -F: &#039;{if ($2 == "") print $1 ": no password!"}&#039;</pre>
<p>There is a way to do this without the command line option. The variable "FS" can be set like any variable, and has the same function as the "-F" command line option. The following is a script that has the same function as the one above.</p>
<pre>#!/bin/awk -f
BEGIN {
FS=":";
}
{
if ( $2 == "" ) {
print $1 ": no password!";
}
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_nopasswd.awk">awk_nopasswd.awk</a></p>
<p>The second form can be used to create a UNIX utility, which I will name "chkpasswd," and executed like this:</p>
<pre>chkpasswd</pre>
<p>The command "chkpasswd -F:" cannot be used, because AWK will never see this argument. All interpreter scripts accept one and only one argument, which is immediately after the  "#!/bin/awk" string. In this case, the single argument is "-f." Another difference between the command line option and the internal variable is the ability to set the input field separator to be more than one character. If you specify</p>
<pre>FS=":  ";</pre>
<p>then AWK will split a line into fields wherever it sees those two characters,  in that exact order. You cannot do this on the command line.</p>
<p>There is a third advantage the internal variable has over  the command line option: you can change the field separator character as many times as you want while reading a file. Well, at most once for each line.  You can even change it depending on the line you read. Suppose you had the following file which contains the numbers 1 through 7 in three different formats. Lines 4 through 6  have colon separated fields, while the others separated by spaces.</p>
<pre>ONE 1 I
 TWO 2 II
 #START
 THREE:3:III
 FOUR:4:IV
 FIVE:5:V
 #STOP
 SIX 6 VI
 SEVEN 7 VII</pre>
<p>The AWK program can easily switch between these formats:</p>
<pre>#!/bin/awk -f
{
if ($1 == "#START") {
FS=":";
} else if ($1 == "#STOP") {
FS=" ";
} else {
#print the Roman number in column 3
print $3
}
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example3.awk">awk_example3.awk</a></p>
<p>Note the field separator variable retains its value until it  is explicitly changed.  You don't have to reset it for each line. Sounds simple, right? However, I have a trick question for you. What happens if you change the field separator while reading a line? That is, suppose you had the following line</p>
<pre>One Two:Three:4 Five</pre>
<p>and you executed the following script:</p>
<pre>#!/bin/awk -f
 {
 print $2
 FS=":"
 print $2
 }</pre>
<p>What would be printed?  "Three" or  "Two:Three:4?" Well, the script would print out "Two:Three:4" twice. However, if you deleted the first print statement, it would print out "Three" once! I thought this was very strange at first, but after pulling out some hair, kicking the deck, and yelling at muself and everyone who had anything to do with the development of UNIX, it is intuitively obvious.  You just have to be thinking like a professional programmer to realize it is intuitive. I shall explain, and prevent you from  causing yourself physical harm.</p>
<p>If you change the field separator <strong>before</strong> you read the line, the change <strong>affects</strong> what you read. If you change it <strong>after</strong> you read the line, it will <strong>not</strong> redefine the variables. You wouldn't want a variable to change on you  as a side-effect of another action. A programming language with hidden side effects is broken, and should not be trusted. AWK allows you to redefine the field separator either before or after you read the line, and does the right thing each time. Once you read the variable, the variable will not change unless you change it. Bravo!</p>
<p>To illustrate this further, here is another version of the  previous code that changes the field separator dynamically.  In this case, AWK does it by examining field  "$0," which is the entire line. When the line contains a colon, the field separator is a colon, otherwise, it is a space:</p>
<pre>#!/bin/awk -f
{
if ( $0 ~ /:/ ) {
FS=":";
} else {
FS=" ";
}
#print the third field, whatever format
print $3
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example4.awk">awk_example4.awk</a></p>
<p>This example eliminates the need to have the special  "#START" and "#STOP" lines in the input.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-16" name="awk-16" id="awk-16" title="OFS - The Output Field Separator Variable">OFS - The Output Field Separator Variable</a></h2>
<p>There is an important difference between</p>
<pre>print $2 $3</pre>
<p>and</p>
<pre>print $2, $3</pre>
<p>The first example prints out one field, and the second prints out two fields. In the first case, the two positional parameters are concatenated together and output without a space. In the second case, AWK prints two fields, and  places the output field separator between them.  Normally this is a space, but you can change this by modifying the variable "OFS."</p>
<p>If you wanted to copy the password file, but delete the encrypted password, you could use AWK:
<pre>#!/bin/awk -f
 BEGIN {
 FS=":";
 OFS=":";
 }
 {
 $2="";
 print }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/delete_passwd.awk">delete_passwd.awk</a></p>
<p>Give this script the password file, and it will delete the password, but leave everything else the same. You can make the output field separator any number of characters. You are not limited to a single character.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-17" name="awk-17" id="awk-17" title="NF - The Number of Fields Variable">NF - The Number of Fields Variable</a></h2>
<p>It is useful to know how many fields are on a line. You may want to have your script change its operation based on the number of fields. As an example, the command  "ls -l" may generate eight or nine fields, depending on which version you are executing. The System V version, "/usr/bin/ls -l" generates nine fields, which is equivalent to the Berkeley "/usr/ucb/ls -lg" command. If you wanted to print the owner and filename then the following AWK script would work with either version of  "ls:"
<pre>#!/bin/awk -f
 # parse the output of "ls -l"
 # print owner and filename
 # remember - Berkeley ls -l has 8 fields, System V has 9
 {
 if (NF == 8) {
 print $3, $8;
 } else if (NF == 9) {
 print $3, $9;
 }
 }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/owner_group.awk">owner_group.awk</a></p>
<p>Don't forget the variable can be prepended with a  "$." This allows you to print the last field of any column
<pre>#!/bin/awk -f
 { print $NF; }</pre>
<p>View file: print_last_field.awk</p>
<p>One warning about AWK. There is a limit of 99 fields in a single line. PERL does not have any such limitations.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-18" name="awk-18" id="awk-18" title="NR - The Number of Records Variable">NR - The Number of Records Variable</a></h2>
<p>Another useful variable is  "NR." This tells you the number of records, or the line number. You can use AWK to only examine certain lines. This example prints lines after the first 100 lines, and puts a line number before each line after 100:
<pre>#!/bin/awk -f
 { if (NR &gt;= 100) {
 print NR, $0; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example5.awk">awk_example5.awk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-19" name="awk-19" id="awk-19" title="RS - The Record Separator Variable">RS - The Record Separator Variable</a></h2>
<p>Normally, AWK reads one line at a time, and breaks up the line into fields. You can set the  "RS" variable to change AWK's definition of a  "line." If you set it to an empty string, then AWK will read the entire file into memory. You can combine this with changing the  "FS" variable. This example treats each line as a field, and prints out the second and third line:</p>
<pre>#!/bin/awk -f
BEGIN {
# change the record separator from newline to nothing
RS=""
# change the field separator from whitespace to newline
FS="n"
}
{
# print the second and third line of the file
print $2, $3;
}
.)l
#!/bin/awk -f
# reports which file is being read
BEGIN {
f="";
}
{  if (f != FILENAME) {
print "reading", FILENAME;
f=FILENAME;
}
print;
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example6.awk">awk_example6.awk</a></p>
<p>The two lines are printed with a space between. Also this will only work if the input file is less than 100 lines, therefore this technique is limited. You can use it to  break words up, one word per line, using this:
<pre>#!/bin/awk -f
 BEGIN {
 RS=" ";
 }
 {
 print ; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/oneword_per_line.awk">oneword_per_line.awk</a></p>
<p>but this only works if all of the words are separated by a space. If there is a tab or punctuation inside, it would not.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-20" name="awk-20" id="awk-20" title="ORS - The Record Separator Variable">ORS - The Record Separator Variable</a></h2>
<p>The default output record separator is a newline, like the input. This can be set to be a newline and carriage return, if you need to generate a text file for a non-UNIX system.
<pre>#!/bin/awk -f
 # this filter adds a carriage return to all lines
 # before the newline character
 BEGIN {
 ORS="rn"
 }
 { print }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/add_cr.awk">add_cr.awk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-21" name="awk-21" id="awk-21" title="FILENAME - The Current Filename Variable">FILENAME - The Current Filename Variable</a></h2>
<p>The last variable known to regular AWK is "FILENAME," which tells you the name of the file being read.
<pre>#!/bin/awk -f
 BEGIN {
 # change the record separator from newline to nothing
 RS=""
 # change the field separator from whitespace to newline
 FS="n"
 }
 {
 # print the second and third line of the file
 print $2, $3;
 }
 .)l
 #!/bin/awk -f
 # reports which file is being read
 BEGIN {
 f="";
 }
 {  if (f != FILENAME) {
 print "reading", FILENAME;
 f=FILENAME;
 }
 print; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example6.awk">awk_example6.awk</a></p>
<p>This can be used if several files need to be parsed by AWK. Normally you use standard input to provide AWK with information. You can also specify the filenames on the command line. If the above script was called  "testfilter," and if you executed it with</p>
<pre>testfilter file1 file2 file3</pre>
<p>It would print out the filename before  each change. An alternate way to specify this on the command line is</p>
<pre>testfilter file1 - file3 &lt;file2
&nbsp;
</pre>
<p>In this case, the second file will be called "-," which is the conventional name for standard input. I have used this when I want to put some information before and after a filter operation. The prefix and postfix files special data before and after the real data. By checking the filename, you can parse the information differently. This is also useful to report syntax errors in particular files:</p>
<pre>#!/bin/awk -f
{
if (NF == 6) {
# do the right thing
} else {
if (FILENAME == "-" ) {
print "SYNTAX ERROR, Wrong number of fields,",
"in STDIN, line #:", NR,  "line: ", $0;
} else {
print "SYNTAX ERROR, Wrong number of fields,",
"Filename: ", FILENAME, "line # ", NR,"line: ", $0;
}
}
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example7.awk">awk_example7.awk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-22" name="awk-22" id="awk-22" title="Associative Arrays">Associative Arrays</a></h2>
<p>I have used dozens of different programming languages over the last 20 years, and AWK is the first language I found that has associative arrays. This term may be meaningless to you, but believe me, these arrays are invaluable, and simplify programming enormously. Let me describe a problem, and show you how associative arrays can be used for reduce coding time, giving you more time to explore another stupid problem you don't want to deal with in the first place.</p>
<p>Let's suppose you have a directory overflowing with files, and you want to  find out how many files are owned by each user, and perhaps  how much disk space each user owns.  You really want someone to blame; it's hard to tell who owns what file. A filter that processes the output of <em>ls</em> would work:</p>
<pre>ls -l | filter</pre>
<p>But this doesn't tell you how much space each user is using. It also doesn't work for a large directory tree. This requires <em>find</em> and <em>xargs</em>:</p>
<pre>find . -type f -print | xargs ls -l | filter</pre>
<p>The third column of "ls" is the username. The filter has to count how many times it sees each user. The typical program would have an array of usernames and another array that counts how many times each username has been seen. The index to both arrays are the same; you use one array to find the index, and the second to keep track of the count. I'll show you one way to do it in AWK--the wrong way:</p>
<pre>#!/bin/awk -f
# bad example of AWK programming
# this counts how many files each user owns.
BEGIN {
number_of_users=0;
}
{
# must make sure you only examine lines with 8 or more fields
if (NF&gt;7) {
user=0;
# look for the user in our list of users
for (i=1; i&lt;=number_of_users; i++) {
#    is the user known?
if (username[i] == $3) {
# found it - remember where the user is
    user=i;
    }
  }
if (user == 0) {
# found a new user
username[++number_of_users]=$3;
user=number_of_users;
  }
# increase number of counts
count[user]++;
}
}
END {
for (i=1; i&lt;=number_of_users; i++) {
print count[i], username[i]
}
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example8.awk">awk_example8.awk</a></p>
<p>I don't want you to <strong>read</strong> this script. I told you it's the wrong way to do it. If you were a C programmer, and didn't know AWK, you would probably use a technique like the one above. Here is the same program, except this example that uses AWK's  associative arrays. The important point is to notice the difference in size between these two versions:
<pre>#!/bin/awk -f
 {
 username[$3]++;
 }
 END {
 for (i in username) {
 print username[i], i;
 } }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/count_users0.awk">count_users0.awk</a></p>
<p>This is shorter, simpler, and <em>much</em> easier to understand--Once you understand exactly what an associative array is. The concept is simple. Instead of using a number to find an entry in an array, use <em>anything you want</em>. An associative array in an array whose index is a string. All arrays in AWK are associative. In this case, the index into the array is the third field of the "ls" command, which is the username. If the user is  "bin," the main loop increments the count per user by effectively executing</p>
<pre> username["bin"]++;</pre>
<p>UNIX guru's may gleefully report that the 8 line AWK script can be replaced by:</p>
<pre>awk &#039;{print $3}&#039; | sort | uniq -c | sort -nr</pre>
<p>True, However, this can't count the total disk space for each user. We need to add some more intelligence to the AWK script, and need the right foundation to proceed. There is also a slight bug in the AWK program. If you wanted a  "quick and dirty" solution, the above would be fine. If you wanted to make it more robust, you have to handle unusual conditions. If you gave this program an empty file for input, you would get the error:</p>
<pre>awk: username is not an array</pre>
<p>Also, if you piped the output of "ls -l" to it, the line that specified the total would increment a non-existing user. There are two techniques used to eliminate this error. The first one only counts valid input:</p>
<pre>#!/bin/awk -f
{
if (NF&gt;7) {
username[$3]++;
}
}
END {
for (i in username) {
print username[i], i;
}
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/count_users1.awk">count_users1.awk</a> This fixes the problem of counting the line with the total. However, it still generates an error when an empty file is read as input. To fix this problem, a common technique is to  make sure the array always exists, and has a special marker value which specifies that the entry is invalid. Then when reporting the results, ignore the invalid entry.</p>
<pre>#!/bin/awk -f
BEGIN {
username[""]=0;
}
{
username[$3]++;
}
END {
for (i in username) {
if (i != "") {
print username[i], i;
  }
}
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/count_users2.awk">count_users2.awk</a></p>
<p>This happens to fix the other problem. Apply this technique and you will make your AWK programs more robust and easier for others to use.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-23" name="awk-23" id="awk-23" title="Multi-dimensional Arrays">Multi-dimensional Arrays</a></h2>
<p>Some people ask if AWK can handle multi-dimensional arrays. It can. However, you don't use conventional two-dimensional arrays. Instead you use associative arrays. (Did I even mention how useful associative arrays are?) Remember, you can put <strong>anything</strong> in the index of an associative array. It requires a different way to think about problems, but once you understand, you won't be able to live without it. All you have to do is to create an index that combines two other indices. Suppose you wanted to effectively execute</p>
<pre> a[1,2] = y;</pre>
<p>This is invalid in AWK. However, the following is perfectly fine:</p>
<pre> a[1 "," 2] = y;</pre>
<p>Remember: the AWK string concatenation operator is the space. It combines the three strings into the single string "1,2." Then it uses it as an index into the array. That's all there is to it. There is one minor problem with associative arrays, especially if you use the <em>for</em> command to output each element: you have no control over the order of output. You can create an algorithm to generate the indices to an associative array, and control the order this way. However, this is difficult to do. Since UNIX provides an excellent sort utility, more programmers separate the information processing from the sorting. I'll show you what I mean.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-24" name="awk-24" id="awk-24" title="Example of using AWK's Associative Arrays">Example of using AWK's Associative Arrays</a></h2>
<p>I often find myself using certain techniques repeatedly in AWK. This example will demonstrate these techniques, and illustrate the power and elegance of AWK. The program is simple and common.  The disk is full. Who's gonna be blamed? I just hope you use this power wisely. Remember, you may be the one who filled up the disk.</p>
<p>Having resolved my moral dilemma, by placing the burden squarely on your  shoulders, I will describe the program in detail. I will also discuss several tips you will find useful in large AWK programs. First, initialize all arrays used in a <em>for</em> loop.  There will be four arrays for this purpose. Initialization is easy:</p>
<pre>u_count[""]=0;
 g_count[""]=0;
 ug_count[""]=0;
 all_count[""]=0;</pre>
<p>The second tip is to pick a convention for arrays. Selecting the names of the arrays, and the indices for each array is very important. In a complex program,  it can become confusing to remember which array contains what. I suggest you clearly identify the indices and contents of each array. To demonstrate, I will use a "_count" to indicate the number of files, and "_sum" to indicate the sum of the file sizes. In addition, the part before the  "_" specifies the index used for the array, which will be either "u" for user, "g" for group, "ug" for the user and group combination, and "all" for the total for all files. In other programs, I have used names like</p>
<pre>username_to_directory[username]=directory;</pre>
<p>Follow a convention like this, and it will be hard for you to forget the purpose of each associative array. Even when a quick hack comes back to haunt you three years later. I've been there.</p>
<p>The third suggestion is to make sure your input is in the correct form. It's generally a  good idea to be pessimistic, but I will add a simple but sufficient test in this example.</p>
<pre>if (NF != 10) {
 #  ignore
 } else {
etc.</pre>
<p>I placed the test and error clause up front, so the rest of the code won't be cluttered. AWK doesn't have user defined functions. NAWK, GAWK and PERL do.</p>
<p>The next piece of advice for complex AWK scripts is to define a name for each field used. In this case, we want the user, group and size in disk blocks. We could use the file size in bytes, but the block size corresponds to the blocks on the disk, a more accurate measurement of space. Disk blocks can be found by using "ls -s." This adds a column, so the username becomes the fourth column, etc. Therefore the script will contain:</p>
<pre>size=$1;
 user=$4;
 group=$5;</pre>
<p>This will allow us to easily adapt to changes in input. We could use "$1" throughout the script, but if we changed the number of fields, which the "-s" option does, we'd have to change each field reference. You don't want to go through an AWK script, and change all the "$1" to  "$2," and also change the  "$2" to "$3" because those are really the "$1" that you just changed to "$2." Of <strong>course</strong> this is confusing. That's why it's a good idea to assign names to the fields. I've been there too.</p>
<p>Next the AWK script will count how many times each combination of users  and groups occur. That is, I am going to construct a two-part index that contains the username and groupname. This will let me count up the number of times each user/group combination occurs, and how much disk space is used.</p>
<p>Consider this: how would you calculate the total for just a user, or for just a group? You could rewrite the script. Or you could take the user/group totals, and total them with a second script.</p>
<p>You could do it, but it's not the AWK way to do it. If you had to examine a bazillion files, and it takes a long time to run that script, it would be a waste to repeat this task. It's also inefficient to require two scripts when one can do everything. The proper way to solve this problem is to extract as much information as possible in one pass through the files. Therefore this script will find the number and size for each category:</p>
<pre>Each user
 Each group
 Each user/group combination
 All users and groups</pre>
<p>This is why I have 4 arrays to count up the number of files. I don't really need 4 arrays, as I can use the format of the index to determine which array is which. But this does maake the program easier to understand for now. The next tip is subtle, but  you will see how useful it is. I mentioned the indices into the array can be anything. If possible, select a format that allows you to merge information from several arrays. I realize this makes no sense right now, but hang in there. All will become clear soon. I will do this by constructing a universal index of the form</p>
<pre>&lt;user&gt;&lt;group&gt;</pre>
<p>This index will be used for all arrays. There is a space between the two values. This covers the total for the user/group combination. What about the other three arrays? I will use a "*" to indicate the total for all users or groups. Therefore the index for all files would be "* *" while the index for all of the file owned by user <em>daemon</em> would be "daemon *." The heart of the script totals up the number and size of each file, putting the information into the right category. I will use 8 arrays; 4 for file sizes, and 4 for counts:</p>
<pre>u_count[user " *"]++;
 g_count["* " group]++;
 ug_count[user " " group]++;
 all_count["* *"]++;
 u_size[user " *"]+=size;
 g_size["* " group]+=size;
 ug_size[user " " group]+=size;
 all_size["* *"]+=size;
&lt;/p&gt;</pre>
<p>This particular universal index will make sorting easier, as you will see. Also important is to sort the information in an order that is useful. You can <strong>try</strong> to force a particular output order in AWK, but why work at this, when it's a one line command for <em>sort</em>? The difficult part is finding the right way to sort the information. This script will sort information using the size of the category as the first sort field. The largest total will be the one for all files, so this will be one of the first lines output. However, there may be several ties for the largest number, and  care must be used.  The second field will be the number of files. This will help break a tie. Still, I want the totals and sub-totals to be listed before the individual user/group combinations. The third and fourth fields will be generated by the index of the array. This is the tricky part I warned you about. The script will output one  string, but the <em>sort</em> utility will not know this. Instead, it will treat it as two fields. This will unify the results, and information from all 4 arrays will look like one array. The sort of the third and fourth fields will be dictionary order, and not numeric,  unlike the first two fields. The  "*" was used so these sub-total fields will be listed before the individual user/group combination.</p>
<p> The arrays will be printed using the following format:</p>
<pre>for (i in u_count) {
 if (i != "") {
 print u_size[i], u_count[i], i;
 }
 }</pre>
<p>I only showed you one array, but all four are printed the same way. That's the essence of the script. The results is sorted, and I converted the space into a tab for cosmetic reasons.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-25" name="awk-25" id="awk-25" title="Output of the script">Output of the script</a></h2>
<p>I changed my directory to <em>/usr/ucb</em>, used the script in that directory. The following is the output:</p>
<pre>size   count   user   group
3173   81      *      *
3173   81      root   *
2973   75      *      staff
2973   75      root   staff
88     3       *      daemon
88     3       root   daemon
64     2       *      kmem
64     2       root   kmem
48     1       *      tty
48     1       root   tty</pre>
<p>This says there are 81 files in this directory, which takes up 3173 disk blocks. All of the files are owned by root. 2973 disk blocks belong to group staff. There are 3 files with group daemon, which takes up 88 disk blocks.</p>
<p>As you can see, the first line of information is the total for all users and groups. The second line is the sub-total for the user "root." The third line is the sub-total for the group "staff." Therefore the order of the sort is useful, with the sub-totals before the individual entries. You could write a simple AWK or grep script to obtain information from just one user or one group, and the information will be easy to sort.</p>
<p>There is only one problem. The <em>/usr/ucb</em> directory on my system only uses 1849 blocks; at least that's what <em>du</em> reports.  Where's the discrepancy? The script does <strong>not</strong> understand hard links. This may not be a problem on most disks, because many users do not use hard links. Still, it does generate inaccurate results. In this case, the program <em>vi</em> is also <em>e</em>, <em>ex</em>, <em>edit</em>, <em>view</em>, and 2 other names. The program only exists once, but has 7 names. You can tell because the link count (field 2) reports 7. This causes the file to be counted 7 times, which causes an inaccurate total. The fix is to only count multiple links once. Examining the link count will determine if a file has multiple links. However, how can you prevent counting a link twice? There is an easy solution: all of these files have the same <em>inode</em> number. You can find this number with the <em>-i</em> option to <em>ls</em>. To save memory, we only have to remember the inodes of files that have multiple links. This means we have to add another column to the input, and have to renumber all of the field references. It's a good thing there are only three. Adding a new field will be easy, because I followed my own advice.</p>
<p>The final script should be easy to follow. I have used variations of this hundreds of times and find it demonstrates the power of AWK as well as provide insight  to a powerful programming paradigm. AWK solves these types of problems easier than most languages. But you have to use AWK the right way.</p>
<p>This is a fully working version of the program, that accurately counts disk space, appears below:</p>
<pre>#!/bin/sh
find . -type f -print | xargs /usr/bin/ls -islg |
awk &#039;
BEGIN {
# initialize all arrays used in for loop
u_count[""]=0;
g_count[""]=0;
ug_count[""]=0;
all_count[""]=0;
}
{
# validate your input
if (NF != 11) {
#  ignore
} else {
# assign field names
inode=$1;
size=$2;
linkcount=$4;
user=$5;
group=$6;
&nbsp;
# should I count this file?
&nbsp;
doit=0;
if (linkcount == 1) {
# only one copy - count it
  doit++;
} else {
# a hard link - only count first one
seen[inode]++;
if (seen[inode] == 1) {
    doit++;
    }
  }
# if doit is true, then count the file
if (doit ) {
&nbsp;
# total up counts in one pass
# use description array names
# use array index that unifies the arrays
&nbsp;
# first the counts for the number of files
&nbsp;
u_count[user " *"]++;
g_count["* " group]++;
ug_count[user " " group]++;
all_count["* *"]++;
&nbsp;
# then the total disk space used
&nbsp;
u_size[user " *"]+=size;
g_size["* " group]+=size;
ug_size[user " " group]+=size;
all_size["* *"]+=size;
  }
}
}
END {
# output in a form that can be sorted
for (i in u_count) {
  if (i != "") {
print u_size[i], u_count[i], i;
      }
}
for (i in g_count) {
  if (i != "") {
print g_size[i], g_count[i], i;
      }
}
for (i in ug_count) {
  if (i != "") {
print ug_size[i], ug_count[i], i;
      }
}
for (i in all_count) {
  if (i != "") {
print all_size[i], all_count[i], i;
      }
}
} &#039; |
# numeric sort - biggest numbers first
# sort fields 0 and 1 first (sort starts with 0)
# followed by dictionary sort on fields 2 + 3
sort +0nr -2 +2d |
# add header
(echo "size count user group";cat -) |
# convert space to tab - makes it nice output
# the second set of quotes contains a single tab character
tr &#039; &#039; &#039;  &#039;
# done - I hope you like it
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/count_users3.awk">count_users3.awk</a></p>
<p>Remember when I said I didn't need to use 4 different arrays?  I can use just one. This is more confusing, but more concise</p>
<pre>#!/bin/sh
find . -type f -print | xargs /usr/bin/ls -islg |
awk &#039;
BEGIN {
# initialize all arrays used in for loop
count[""]=0;
}
{
# validate your input
if (NF != 11) {
#  ignore
} else {
# assign field names
inode=$1;
size=$2;
linkcount=$4;
user=$5;
group=$6;
&nbsp;
# should I count this file?
&nbsp;
doit=0;
if (linkcount == 1) {
# only one copy - count it
  doit++;
} else {
# a hard link - only count first one
seen[inode]++;
if (seen[inode] == 1) {
    doit++;
    }
  }
# if doit is true, then count the file
if (doit ) {
&nbsp;
# total up counts in one pass
# use description array names
# use array index that unifies the arrays
&nbsp;
# first the counts for the number of files
&nbsp;
count[user " *"]++;
count["* " group]++;
count[user " " group]++;
count["* *"]++;
&nbsp;
# then the total disk space used
&nbsp;
size[user " *"]+=size;
size["* " group]+=size;
size[user " " group]+=size;
size["* *"]+=size;
  }
}
}
END {
# output in a form that can be sorted
for (i in count) {
if (i != "") {
print size[i], count[i], i;
  }
}
} &#039; |
&nbsp;
# numeric sort - biggest numbers first
# sort fields 0 and 1 first (sort starts with 0)
# followed by dictionary sort on fields 2 + 3
sort +0nr -2 +2d |
# add header
(echo "size count user group";cat -) |
# convert space to tab - makes it nice output
# the second set of quotes contains a single tab character
tr &#039; &#039; &#039;  &#039;
# done - I hope you like it
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/count_users.awk">count_users.awk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-26" name="awk-26" id="awk-26" title="Picture Perfect PRINTF Output">Picture Perfect PRINTF Output</a></h2>
<p>So far, I described several simple scripts that provide useful information, in a somewhat ugly output format. Columns might not line up properly, and it is often hard to find patterns or trends without this unity. As you use AWK more, you will be desirous of crisp, clean formatting. To achieve this, you must master the <em>printf</em> function.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-27" name="awk-27" id="awk-27" title="PRINTF - formatting output">PRINTF - formatting output</a></h2>
<p>The <em>printf</em> is very similar to the C function with the same name. C programmers should have no problem using <em>printf</em> function.</p>
<p> <em>Printf</em> has one of these syntactical forms:</p>
<pre>printf ( format);
 printf ( format, arguments...);
 printf ( format) &gt;expression;
 printf ( format, arguments...) &gt; expression;</pre>
<p>The parenthesis and semicolon are optional. I only use the first format to be consistent with other nearby <em>printf</em> statements. A <em>print</em> statement would do the same thing. <em>Printf</em> reveals it's real power when formatting commands are used.</p>
<p>The first argument to the <em>printf</em> function is the format.  This is a string, or variable whose value is a string. This string, like all strings, can contain special  escape sequences to print control characters.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-28" name="awk-28" id="awk-28" title="Escape Sequences">Escape Sequences</a></h2>
<p>The character "" is used to  "escape" or mark special characters. The list of these characters is in table  below:</p>
<pre>+-------------------------------------------------------+
|      AWK Table 5        |
|          Escape Sequences        |
|Sequence   Description          |
+-------------------------------------------------------+
|a        ASCII bell (NAWK only)        |
|b        Backspace            |
|f        Formfeed            |
|n        Newline            |
|r        Carriage Return          |
|t        Horizontal tab          |
|v        Vertical tab (NAWK only)        |
|ddd        Character (1 to 3 octal digits) (NAWK only) |
|xdd        Character (hexadecimal) (NAWK only)    |
|        Any character c          |
+-------------------------------------------------------+</pre>
<p> It's difficult to explain the differences without being wordy. Hopefully I'll provide enough examples  to demonstrate the differences.</p>
<p>With NAWK, you can print three tab characters using these three different representations:</p>
<pre>printf("t11x9n");</pre>
<p>A tab character is decimal 11, or hexadecimal 9. See the man page ascii(7) for more information. Similarly, you can print three double-quote characters  (decimal 42, hexadecimal 22) using</p>
<pre>printf(""x2242n");</pre>
<p>You should notice a difference between the <em>printf</em> function and the <em>print</em> function. <em>Print</em> terminates the line with the <strong>OFS</strong> character, and divides each field with the <strong>ORS</strong> separator. <em>Printf</em> does nothing unless you specify the action. Therefore you will frequently end each line with the newline character "n," and you must specify the separating characters explicitly.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-29" name="awk-29" id="awk-29" title="Format Specifiers">Format Specifiers</a></h2>
<p>The power of the <em>printf</em> statement lies in the format specifiers, which always start with the character  "%." The format specifiers are described in table 6:</p>
<pre>+----------------------------------------+
|    AWK Table 6      |
|       Format Specifiers      |
|Specifier   Meaning        |
+----------------------------------------+
|c        ASCII Character      |
|d        Decimal integer      |
|e        Floating Point number    |
|        (engineering format)    |
|f        Floating Point number    |
|        (fixed point format)    |
|g        The shorter of e or f,    |
|        with trailing zeros removed |
|o        Octal        |
|s        String        |
|x        Hexadecimal      |
|%        Literal %        |
+----------------------------------------+</pre>
<p>Again, I'll cover the differences quickly. Table 3 illustrates the differences. The first line states "printf(%cn",100.0)"" prints a "d."</p>
<pre>+--------------------------------+
|    AWK Table 7        |
| Example of format conversions  |
|Format   Value   Results      |
+--------------------------------+
|%c       100.0   d        |
|%c       "100.0"   1 (NAWK?)    |
|%c       42   "        |
|%d       100.0   100        |
|%e       100.0   1.000000e+02 |
|%f       100.0   100.000000   |
|%g       100.0   100        |
|%o       100.0   144        |
|%s       100.0   100.0        |
|%s       "13f"   13f        |
|%d       "13f"   0 (AWK)      |
|%d       "13f"   13 (NAWK)    |
|%x       100.0   64        |
+--------------------------------+</pre>
<p>This table reveals some differences between  AWK and NAWK. When a string with numbers and letters are coverted into an integer, AWK will return a zero, while NAWK will convert as much as possible. The second example, marked with  "NAWK?" will return "d" on some earlier versions of NAWK, while later versions will return "1."</p>
<p>Using format specifiers, there is another way to print a  double quote with NAWK. This demonstrates Octal, Decimal and Hexadecimal conversion. As you can see, it isn't symmetrical. Decimal conversions are done differently.</p>
<pre>printf("%s%s%s%cn", """, "x22", "42", 34);</pre>
<p>Between the  "%" and the format character can be four optional pieces of information. It helps to visualize these fields as:</p>
<pre>%
&lt;sign&gt;
&lt;zero&gt;
&lt;width&gt;
.
&lt;precision&gt;
format</pre>
<p>I'll discuss each one separately.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-30" name="awk-30" id="awk-30" title="Width - specifying minimum field size">Width - specifying minimum field size</a></h2>
<p>If there is a number after the "%," this specifies the minimum number of characters to print. This is the <em>width</em> field. Spaces are added so the number of printed characters equal this number.  Note that this is the minimum field size. If the field becomes to large, it will grow, so information will not be lost. Spaces are added to the left.</p>
<p>This format allows you to line up columns perfectly. Consider the following format:</p>
<pre>printf("%st%dn", s, d);</pre>
<p>If the string  "s" is longer than 8 characters, the columns won't line up. Instead, use</p>
<pre>printf("%20s%dn", s, d);</pre>
<p>As long as the string is less than 20 characters, the number will start on the 21st column. If the string is too long, then the two fields will run together, making it hard to read. You may want to consider placing a single space between the fields, to make sure you will always have one space between the fields. This is very important if you want to  pipe the output to another program.</p>
<p>Adding informational headers makes the output more readable. Be aware that changing the format of the data may make it difficult to get the columns aligned perfectly. Consider the following script:
<pre>#!/usr/bin/awk -f
 BEGIN {
 printf("String     Numbern");
 }
 {
 printf("%10s %6dn", $1, $2); }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example9.awk">awk_example9.awk</a> It would be awkward (forgive the choice of words) to add a new column and retain the same alignment. More complicated formats would require a lot of trial and error. You have to adjust the first <em>printf</em> to agree with the second <em>printf</em> statement. I suggest
<pre>#!/usr/bin/awk -f
 BEGIN {
 printf("%10s %6sn", "String", "Number");
 }
 {
 printf("%10s %6dn", $1, $2); }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example10.awk">awk_example10.awk</a></p>
<p>or even better
<pre>#!/usr/bin/awk -f
 BEGIN {
 format1 ="%10s %6sn";
 format2 ="%10s %6dn";
 printf(format1, "String", "Number");
 }
 {
 printf(format2, $1, $2); }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example11.awk">awk_example11.awk</a></p>
<p>The last example, by using string variables for formatting, allows you to keep all of the formats together.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-31" name="awk-31" id="awk-31" title="Left Justification">Left Justification</a></h2>
<p>The last example places spaces before each field to make sure the minimum field width is met. What do you do if you want the spaces on the right? Add a negative sign before the width:</p>
<pre> printf("%-10s %-6dn", $1, $2);</pre>
<p>This will move the printing characters to the left, with spaces added to the right.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-32" name="awk-32" id="awk-32" title="The Field Precision Value">The Field Precision Value</a></h2>
<p>The precision field, which is the number between the decimal and the format character, is more complex. Most people use it with the floating point format (%f), but surprisingly, it can be used with any format character. With the octal, decimal or hexadecimal format, it specifies the minimum number of characters. Zeros are added to met this requirement. With the %e and %f formats, it specifies the number of digits after the decimal point.  The %e  "e+00" is not included in the precision. The %g format combines the characteristics of the %d and %f formats. The precision specifies the number of digits displayed, before and after the decimal point. The precision field has no effect on the %c field. The %s format has an unusual, but useful effect: it specifies the maximum number of significant characters to print.</p>
<p>If the first number after the  "%," or after the "%-," is a zero, then the system adds zeros when padding. This includes all format types, including strings and the %c character format. This means  "%010d" and  "%.10d" both adds leading zeros, giving a minimum of 10 digits. The format "%10.10d" is therefore redundant. Table 8 gives some examples:</p>
<pre>+--------------------------------------------+
|    AWK Table 8        |
|      Examples of complex formatting      |
|Format    Variable     Results      |
+--------------------------------------------+
|%c    100       "d"        |
|%10c    100       "       d"      |
|%010c    100       "000000000d"      |
+--------------------------------------------+
|%d    10       "10"        |
|%10d    10       "      10"      |
|%10.4d    10.123456789     "    0010"      |
|%10.8d    10.123456789     "  00000010"      |
|%.8d    10.123456789     "00000010"      |
|%010d    10.123456789     "0000000010"      |
+--------------------------------------------+
|%e    987.1234567890   "9.871235e+02"   |
|%10.4e    987.1234567890   "9.8712e+02"      |
|%10.8e    987.1234567890   "9.87123457e+02" |
+--------------------------------------------+
|%f    987.1234567890   "987.123457"      |
|%10.4f    987.1234567890   "  987.1235"      |
|%010.4f    987.1234567890   "00987.1235"      |
|%10.8f    987.1234567890   "987.12345679"   |
+--------------------------------------------+
|%g    987.1234567890   "987.123"      |
|%10g    987.1234567890   "   987.123"      |
|%10.4g    987.1234567890   "   987.1"      |
|%010.4g    987.1234567890   "00000987.1"      |
|%.8g    987.1234567890   "987.12346"      |
+--------------------------------------------+
|%o    987.1234567890   "1733"      |
|%10o    987.1234567890   "    1733"      |
|%010o    987.1234567890   "0000001733"      |
|%.8o    987.1234567890   "00001733"      |
+--------------------------------------------+
|%s    987.123     "987.123"      |
|%10s    987.123     "   987.123"      |
|%10.4s    987.123     "    987."      |
|%010.8s    987.123     "000987.123"      |
+--------------------------------------------+
|%x    987.1234567890   "3db"      |
|%10x    987.1234567890   "     3db"      |
|%010x    987.1234567890   "00000003db"      |
|%.8x    987.1234567890   "000003db"      |
+--------------------------------------------+</pre>
<p>There is one more topic needed to complete this lesson on <em>printf</em>.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-33" name="awk-33" id="awk-33" title="Explicit File output">Explicit File output</a></h2>
<p>Instead of sending output to standard output, you can send output to a named file. The format is</p>
<pre>printf("stringn") &gt; "/tmp/file";</pre>
<p>You can append to an existing file, by using "&gt;&gt;:"</p>
<pre>printf("stringn") &gt;&gt; "/tmp/file";</pre>
<p>Like the shell, the double angle brackets indicates output is <strong>appended</strong> to the file, instead of <strong>written</strong> to an empty file. Appending to the file does not delete the old contents. However, there is a subtle difference between AWK and the shell.</p>
<p>Consider the shell program:</p>
<pre>#!/bin/sh
 while x=`line`
 do
 echo got $x &gt;&gt;/tmp/a
 echo got $x &gt;/tmp/b
 done</pre>
<p>This will read standard input, and copy the standard input to files "/tmp/a" and  "/tmp/b." File  "/tmp/a" will grow larger, as information is always appended to the file. File  "/tmp/b," however, will only contain one line. This happens because each time the shell see the "&gt;" or "&gt;&gt;" characters, it opens the file for writing, choosing the truncate/create or appending option at that time.</p>
<p>Now consider the equivalent AWK program:</p>
<pre>#!/usr/bin/awk -f
 {
 print $0 &gt;&gt;"/tmp/a"
 print $0 &gt;"/tmp/b"
 }</pre>
<p>This behaves differently. AWK chooses the create/append option the first time a file is opened for writing. Afterwards, the use of  "&gt;" or "&gt;&gt;" is ignored. Unlike the shell, AWK copies all of standard input to file "/tmp/b."</p>
<p>Instead of a string, some versions of AWK allow you to specify an expression:</p>
<pre># [note to self] check this one - it might not work
 printf("stringn") &gt; FILENAME ".out";</pre>
<p>The following uses a string concatenation expression to illustrate this:
<pre>#!/usr/bin/awk -f
 END {
 for (i=0;i&lt;30;i++) {
 printf("i=%dn", i) &gt; "/tmp/a" i;
 } }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example12.awk">awk_example12.awk</a> This script never finishes, because  AWK can have 10 additional files open, and NAWK can have 20. If you find this to be a problem, look into PERL.</p>
<p>I hope this gives you the skill to make your AWK output picture perfect.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-34" name="awk-34" id="awk-34" title="AWK Numerical Functions">AWK Numerical Functions</a></h2>
<p>In previous tutorials, I have shown how useful AWK is in manipulating  information, and generating reports. When you add a few functions, AWK becomes even more, mmm, functional.</p>
<p>There are three types of functions: numeric, string and whatever's left. Table9 lists all of the numeric functions:</p>
<pre>+----------------------------------+
|    AWK Table 9         |
+----------------------------------+
|       Numeric Functions         |
|Name    Function     Variant     |
+----------------------------------+
|cos     cosine     AWK         |
|exp     Exponent     AWK         |
|int     Integer     AWK         |
|log     Logarithm     AWK         |
|sin     Sine     AWK         |
|sqrt    Square Root   AWK         |
|atan2   Arctangent     NAWK         |
|rand    Random     NAWK         |
|srand   Seed Random   NAWK         |
+----------------------------------+</pre>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-35" name="awk-35" id="awk-35" title="Trigonometric Functions">Trigonometric Functions</a></h2>
<p>Oh joy. I bet millions, if not dozens, of my readers have been waiting for me to discuss trigonometry. Personally, I don't use trigonometry much at work, except when I go off on a tangent.</p>
<p>Sorry about that. I don't know what came over me. I don't usually resort to puns. I'll write a note to myself, and after I sine the note, I'll have  my boss cosine it.</p>
<p><strong>Now stop that!</strong> I hate arguing with myself. I always lose. Thinking about math I learned in the year 2 B.C. (Before Computers) seems to cause flashbacks of high school, pimples, and (shudder) times best left forgotten. The stress of remembering those days must have made me forget the standards I normally set for myself. Besides, no-one appreciates obtuse humor anyway, even if I find acute  way to say it.</p>
<p>I better change the subject fast.  Combining humor and computers is a very serious matter.</p>
<p>Here is a NAWK script that calculates the trigonometric functions for all degrees between 0 and 360. It also shows why there is no tangent, secant or cosecant function. (They aren't necessary). If you read the  script, you will learn of some subtle differences between AWK and NAWK. All this in a thin veneer of demonstrating why we learned trigonometry in the first place. What more can you ask for? Oh, in case you are wondering, I wrote this in the month of December.</p>
<pre>#!/usr/bin/nawk -f
#
# A smattering of trigonometry...
#
# This AWK script plots the values from 0 to 360
# for the basic trigonometry functions
# but first - a review:
#
# (Note to the editor - the following diagram assumes
# a fixed width font, like Courier.
# otherwise, the diagram  looks very stupid, instead of slightly stupid)
#
# Assume the following right triangle
#
#       Angle Y
#
#       |
#       |
#       |
#     a |     c
#       |
#       |
#       +-------   Angle X
#          b
#
# since the triangle is a right angle, then
#  X+Y=90
#
# Basic Trigonometric Functions. If you know the length
# of 2 sides, and the angles, you can find the length of the third side.
# Also - if you know the length of the sides, you can calculate
# the angles.
#
# The formulas are
#
#  sine(X) = a/c
#  cosine(X) = b/c
#  tangent(X) = a/b
#
# reciprocal functions
#  cotangent(X) = b/a
#  secant(X) = c/b
#  cosecant(X) = c/a
#
# Example 1)
# if an angle is 30, and the hypotenuse (c) is 10, then
#   a = sine(30) * 10 = 5
#  b = cosine(30) * 10 =  8.66
#
# The second example will be more realistic:
#
#   Suppose you are looking for a Christmas tree, and
# while talking to your family, you smack into a tree
# because your head was turned, and your kids were arguing over who
# was going to put the first ornament on the tree.
#
# As you come to, you realize your feet are touching the trunk of the tree,
# and your eyes are 6 feet from the bottom of your frostbitten toes.
# While counting the stars that spin around your head, you also realize
# the top of the tree is located at a 65 degree angle, relative to your eyes.
&nbsp;
# You suddenly realize the tree is 12.84 feet high! After all,
#   tangent(65 degrees) * 6 feet = 12.84 feet
&nbsp;
# All right, it isn&#039;t realistic. Not many people memorize the
# tangent table, or can estimate angles that accurately.
# I was telling the truth about the stars spinning around the head, however.
&nbsp;
#
BEGIN {
# assign a value for pi.
PI=3.14159;
# select an "Ed Sullivan" number - really really big
BIG=999999;
# pick two formats
# Keep them close together, so when one column is made larger
# the other column can be adjusted to be the same width
fmt1="%7s %8s %8s %8s %10s %10s %10s %10sn";
# print out the title of each column
fmt2="%7d %8.2f %8.2f %8.2f %10.2f %10.2f %10.2f %10.2fn";
# old AWK wants a backslash at the end of the next line
# to continue the print statement
# new AWK allows you to break the line into two, after a comma
printf(fmt1,"Degrees","Radians","Cosine","Sine",
"Tangent","Cotangent","Secant", "Cosecant");
&nbsp;
for (i=0;i&lt;=360;i++) {
# convert degrees to radians
r = i * (PI / 180 );
# in new AWK, the backslashes are optional
# in OLD AWK, they are required
printf(fmt2, i, r,
# cosine of r
cos(r),
# sine of r
sin(r),
#
# I ran into a problem when dividing by zero.
# So I had to test for this case.
#
# old AWK finds the next line too complicated
# I don&#039;t mind adding a backslash, but rewriting the
# next three lines seems pointless for a simple lesson.
# This script will only work with new AWK, now - sigh...
# On the plus side,
#   I don&#039;t need to add those back slashes anymore
#
# tangent of r
(cos(r) == 0) ? BIG : sin(r)/cos(r),
# cotangent of r
(sin(r) == 0) ? BIG : cos(r)/sin(r),
# secant of r
(cos(r) == 0) ? BIG : 1/cos(r),
# cosecant of r
(sin(r) == 0) ? BIG : 1/sin(r));
}
# put an exit here, so that standard input isn&#039;t needed.
exit;
}</pre>
<p>View file: trigonometry.awk</p>
<p>NAWK also has the arctangent function. This is useful for some graphics work, as</p>
<pre>arc tangent(a/b) = angle (in radians)</pre>
<p>Therefore if you have the X and Y locations, the arctangent of the ratio will tell you the angle. The <em>atan2</em>() function returns a value from negative <em>pi</em> to positive <em>pi</em>.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-36" name="awk-36" id="awk-36" title="Exponents, logs and square roots">Exponents, logs and square roots</a></h2>
<p>The following script uses three other arithmetic functions: <em>log</em>, <em>exp</em>, and <em>sqrt</em>. I wanted to show how these can be used together, so I divided the log of a number by two, which is another way to find a square root. I then compared the value of the exponent of that new log to the built-in square root function. I then calculated the difference between the two, and converted the difference into a positive number.</p>
<pre>#!/bin/awk -f
# demonstrate use of exp(), log() and sqrt in AWK
# e.g. what is the difference between using logarithms and regular arithmetic
# note - exp and log are natural log functions - not base 10
#
BEGIN {
# what is the about of error that will be reported?
ERROR=0.000000000001;
# loop a long while
for (i=1;i&lt;=2147483647;i++) {
# find log of i
logi=log(i);
# what is square root of i?
# divide the log by 2
logsquareroot=logi/2;
# convert log of i back
squareroot=exp(logsquareroot);
# find the difference between the logarithmic calculation
# and the built in calculation
diff=sqrt(i)-squareroot;
# make difference positive
if (diff &lt; 0) {
  diff*=-1;
  }
if (diff &gt; ERROR) {
printf("%10d, squareroot: %16.8f, error: %16.14fn",
i, squareroot, diff);
  }
}
exit;
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example13.awk">awk_example13.awk</a> Yawn. This example isn't too exciting, except to those who enjoy nitpicking. Expect the program to reach 3 million before you see any errors. I'll give you a more exciting sample soon.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-37" name="awk-37" id="awk-37" title="Truncating Integers">Truncating Integers</a></h2>
<p>All version of AWK contain the <em>int</em> function. This truncates a number, making it an integer. It can be used to round numbers by adding 0.5:</p>
<pre>printf("rounding %8.4f gives %8dn", x, int(x+0.5));</pre>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-38" name="awk-38" id="awk-38" title="Random Numbers">Random Numbers</a></h2>
<p>NAWK has functions that can generate random numbers. The function <em>rand</em> returns a random number between 0 and 1. Here is an example that calculates a million random numbers between 0 and 100, and counts how often each number was used:</p>
<pre>#!/usr/bin/nawk -f
# old AWK doesn&#039;t have rand() and srand()
# only new AWK has them
# how random is the random function?
BEGIN {
#  srand();
i=0;
while (i++&lt;1000000) {
x=int(rand()*100 + 0.5);
y[x]++;
}
for (i=0;i&lt;=100;i++) {
printf("%dt%dn",y[i],i);
}
exit;
}</pre>
<p>View file: random.awk</p>
<p>If you execute this script several times, you will get the exact same results. Experienced programmers know random number generators aren't really random, unless they use special hardware. These numbers are pseudo-random, and calculated using some algorithm. Since the algorithm is fixed, the numbers are repeatable unless the numbers are seeded with a unique value. This is done using the <em>srand</em> function above, which is commented out. Typically the random number generator is not given a special seed until the bugs have been worked out of the program. There's nothing more frustrating than a bug that occurs randomly. The <em>srand</em> function may be given an argument. If not, it uses the current time and day to generate a seed for the random number generator.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-39" name="awk-39" id="awk-39" title="The Lotto script">The Lotto script</a></h2>
<p>I promised a more useful script. This may be what you are waiting for. It reads two numbers, and generates a list of random numbers. I call the script "lotto.awk."</p>
<pre>#!/usr/bin/nawk -f
BEGIN {
# Assume we want 6 random numbers between 1 and 36
# We could get this information by reading standard input,
# but this example will use a fixed set of parameters.
#
# First, initialize the seed
srand();
# How many numbers are needed?
NUM=6;
# what is the minimum number
MIN=1;
# and the maximum?
MAX=36;
# How many numbers will we find? start with 0
Number=0;
while (Number &lt; NUM) {
r=int(((rand() *(1+MAX-MIN))+MIN));
# have I seen this number before?
if (array[r] == 0) {
# no, I have not
Number++;
array[r]++;
}
}
&nbsp;
# now output all numbers, in order
for (i=MIN;i&lt;=MAX;i++) {
# is it marked in the array?
if (array[i]) {
# yes
printf("%d ",i);
}
}
printf("n");
exit;
}</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/lotto.awk">lotto.awk</a> If you do win a lottery, send me a postcard.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-40" name="awk-40" id="awk-40" title="String Functions">String Functions</a></h2>
<p>Besides numeric functions, there are two other types of function:  strings and the whatchamacallits.  First, a list of the string functions:</p>
<pre>+-------------------------------------------------+
|      AWK Table 10           |
|          String Functions           |
|Name             Variant         |
+-------------------------------------------------+
|index(string,search)         AWK, NAWK, GAWK |
|length(string)           AWK, NAWK, GAWK |
|split(string,array,separator)    AWK, NAWK, GAWK |
|substr(string,position)         AWK, NAWK, GAWK |
|substr(string,position,max)      AWK, NAWK, GAWK |
|sub(regex,replacement)         NAWK, GAWK      |
|sub(regex,replacement,string)    NAWK, GAWK      |
|gsub(regex,replacement)         NAWK, GAWK      |
|gsub(regex,replacement,string)   NAWK, GAWK      |
|match(string,regex)         NAWK, GAWK      |
|tolower(string)           GAWK         |
|toupper(string)           GAWK         |
+-------------------------------------------------+</pre>
<p>Most people first use AWK to perform simple calculations. Associative arrays and trigonometric functions are somewhat esoteric features, that new users embrace with the eagerness of a chain smoker in a fireworks factory. I suspect most users add some simple string functions to their repertoire once they want to add a little more sophistication to their AWK scripts. I hope this column gives you enough information to inspire your next effort.</p>
<p>There are four string functions in the original AWK: <em>index</em>(), <em>length</em>(), <em>split</em>(), and <em>substr</em>(). These functions are quite versatile.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-41" name="awk-41" id="awk-41" title="The Length function">The Length function</a></h2>
<p>What can I say? The <em>length</em>() function calculates the length of a string. I often use it to make sure my input is correct. If you wanted to ignore empty lines, check the length of the each line before processing it with</p>
<pre>if (length($0) &gt; 1) {
 . . .
 }</pre>
<p>You can easily use it to print all lines longer than a certain length, etc. The following command centers all lines shorter than 80 characters:
<pre>#!/bin/awk -f
 {
 if (length($0) &lt; 80) {
 prefix = "";
 for (i = 1;i&lt;(80-length($0))/2;i++)
 prefix = prefix " ";
 print prefix $0;
 } else {
 print;
 } }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/center.awk">center.awk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-42" name="awk-42" id="awk-42" title="The Index Function">The Index Function</a></h2>
<p>If you want to search for a special character, the <em>index</em>() function will search for specific characters inside a string. To find a comma, the code might look like this:</p>
<pre>sentence="This is a short, meaningless sentence.";
 if (index(sentence, ",") &gt; 0) {
 printf("Found a comma in position %dn", index(sentence,","));
 }</pre>
<p>The function returns a positive value when the substring is found. The number specified the location of the substring.</p>
<p>If the substring consists of 2 or more characters, all of these characters must be found, in the same order, for a non-zero return value. Like the <em>length</em>() function, this is useful for checking for proper input conditions.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-43" name="awk-43" id="awk-43" title="The Substr function">The Substr function</a></h2>
<p>The <em>substr</em>() function can extract a portion of a string. One common use is to split a string into two parts based on a special character. If you wanted to process some mail addresses, the following code fragment might do the job:
<pre>#!/bin/awk -f
 {
 # field 1 is the e-mail address - perhaps
 if ((x=index($1,"@")) &gt; 0) {
 username = substr($1,1,x-1);
 hostname = substr($1,x+1,length($1));
 # the above is the same as
 #        hostname = substr($1,x+1);
 printf("username = %s, hostname = %sn", username, hostname);
 } }</pre>
<p>View file: email.awk The <em>substr</em>() function takes two or three arguments. The first is the string, the second is the position. The optional third argument is the length of the string to extract. If the third argument is missing, the rest of the string is used.</p>
<p>The substr function can be used in many non-obvious ways. As an example, it can be used to convert upper case letters to lower case.</p>
<pre>#!/usr/bin/awk -f
# convert upper case letters to lower case
BEGIN {
LC="abcdefghijklmnopqrstuvwxyz";
UC="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
{
out="";
# look at each character
for(i=1;i&lt;=length($0);i++) {
# get the character to be checked
char=substr($0,i,1);
# is it an upper case letter?
j=index(UC,char);
if (j &gt; 0 ) {
# found it
out = out substr(LC,j,1);
} else {
out = out char;
}
}
printf("%sn", out);
}
</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/upper_to_lower.awk">upper_to_lower.awk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-44" name="awk-44" id="awk-44" title="GAWK's Tolower and Toupper function">GAWK's Tolower and Toupper function</a></h2>
<p>GAWK has the <em>toupper</em>() and <em>tolower</em>() functions, for convenient conversions of case. These functions take strings, so you can reduce the above script to a single line:
<pre>#!/usr/local/bin/gawk -f
 {
 print tolower($0); }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/upper_to_lower.gawk">upper_to_lower.gawk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-45" name="awk-45" id="awk-45" title="The Split function">The Split function</a></h2>
<p>Another way to split up a string is to use the <em>split</em>() function. It takes three arguments: the string, an array, and the separator. The function returns the number of pieces found. Here is an example:
<pre>#!/usr/bin/awk -f
 BEGIN {
 # this script breaks up the sentence into words, using
 # a space as the character separating the words
 string="This is a string, is it not?";
 search=" ";
 n=split(string,array,search);
 for (i=1;i&lt;=n;i++) {
 printf("Word[%d]=%sn",i,array[i]);
 }
 exit; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example14.sh">awk_example14.sh</a></p>
<p>The third argument is typically a single character. If a longer string is used, only the first letter is used as a separator.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-46" name="awk-46" id="awk-46" title="NAWK's string functions">NAWK's string functions</a></h2>
<p>NAWK (and GAWK) have additional string functions, which add  a primitive SED-like functionality: <em>sub</em>(), <em>match</em>(), and <em>gsub</em>().</p>
<p> <em>Sub</em>() performs a string substitution, like <em>sed</em>. To replace "old" with "new" in a string, use</p>
<pre>sub(/old/, "new", string)</pre>
<p>If the third argument is missing, $0 is assumed to be string searched. The function returns 1 if a substitution occurs, and 0 if not. If no slashes are given in the first argument, the first argument is assumed to be a variable containing a regular expression. The <em>sub</em>() only changes the first occurrence. The <em>gsub</em>() function is similar to the <strong>g</strong> option in <em>sed</em>: all occurrence are converted, and not just the first. That is, if the patter occurs more than once per line (or string), the substitution will be performed once for each found pattern. The following script:
<pre>#!/usr/bin/nawk -f
 BEGIN {
 string = "Another sample of an example sentence";
 pattern="[Aa]n";
 if (gsub(pattern,"AN",string)) {
 printf("Substitution occurred: %sn", string);
 }
&nbsp;
 exit; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example15.awk">awk_example15.awk</a></p>
<p>print the following when executed:</p>
<pre>Substitution occurred: ANother sample of AN example sentence</pre>
<p>As you can see, the pattern can be a regular expression.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-47" name="awk-47" id="awk-47" title="The Match function">The Match function</a></h2>
<p>As the above demonstrates, the <em>sub</em>() and <em>gsub</em>() returns a positive value if a match is found. However, it has a side-effect of changing the string tested. If you don't wish this, you can copy the string to another variable, and test the spare variable. NAWK also provides the <em>match</em>() function. If <em>match</em>() finds the regular expression, it sets two special variables that indicate where the regular expression begins and ends. Here is an example that does this:
<pre>#!/usr/bin/nawk -f
 # demonstrate the match function
&nbsp;
 BEGIN {
 regex="[a-zA-Z0-9]+";
 }
 {
 if (match($0,regex)) {
 #           RSTART is where the pattern starts
 #           RLENGTH is the length of the pattern
 before = substr($0,1,RSTART-1);
 pattern = substr($0,RSTART,RLENGTH);
 after = substr($0,RSTART+RLENGTH);
 printf("%s&lt;%s&gt;%sn", before, pattern, after);
 } }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example16.awk">awk_example16.awk</a></p>
<p>Lastly, there are the whatchamacallit functions. I could use the word "miscellaneous," but it's too hard to spell. Darn it, I had to look it up anyway.</p>
<pre>+-----------------------------------------------+
|      AWK Table 11          |
|      Miscellaneous Functions        |
|Name            Variant        |
+-----------------------------------------------+
|getline            AWK, NAWK, GAWK |
|getline &lt;file          NAWK, GAWK      |
|getline variable          NAWK, GAWK      |
|getline variable &lt;file      NAWK, GAWK      |
|"command" | getline        NAWK, GAWK      |
|"command" | getline variable   NAWK, GAWK      |
|system(command)          NAWK, GAWK      |
|close(command)          NAWK, GAWK      |
|systime()          GAWK        |
|strftime(string)          GAWK        |
|strftime(string, timestamp)    GAWK        |
+-----------------------------------------------+</pre>
<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-48" name="awk-48" title="The System function" id="awk-48">The System function</a></h2>
<p>NAWK has a function <em>system</em>() that can execute any program. It returns the exit status of the program.</p>
<pre>if (system("/bin/rm junk") != 0)
 print "command didn&#039;t work";</pre>
<p>The command can be a string, so you can dynamically create commands based on input. Note that the output isn't sent to the NAWK program. You could send it to a file, and open that file for reading. There is another solution, however.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-49" name="awk-49" title="The Getline function" id="awk-49">The Getline function</a></h2>
<p>AWK has a command that allows you to force a new line. It doesn't take any arguments. It returns a 1, if successful, a 0 if end-of-file is reached, and a -1 if an error occurs. As a side effect, the line containing the input changes. This next script filters the input, and if a backslash occurs at the end of the line, it reads the next line in, eliminating the backslash as well as the need for it.
<pre>#!/usr/bin/awk -f
 # look for a  as the last character.
 # if found, read the next line and append
 {
 line = $0;
 while (substr(line,length(line),1) == "") {
 # chop off the last character
 line = substr(line,1,length(line)-1);
 i=getline;
 if (i &gt; 0) {
 line = line $0;
 } else {
 printf("missing continuation on line %dn", NR);
 }
 }
 print line; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example17.awk">awk_example17.awk</a></p>
<p>Instead of reading into the standard variables, you can specify the variable to set:</p>
<pre>getline a_line
 print a_line;</pre>
<p>NAWK  and GAWK allow the <em>getline</em> function to be given an optional filename or string containing a filename. An example of a primitive file preprocessor, that looks for lines of the format</p>
<pre>#include filename</pre>
<p>and substitutes that line for the contents of the file:
<pre>#!/usr/bin/nawk -f
 {
 # a primitive include preprocessor
 if (($1 == "#include") &amp;amp;&amp;amp; (NF == 2)) {
 # found the name of the file
 filename = $2;
 while (i = getline &lt; filename ) {
 print;
 }
 } else {
 print;
 } }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/include.nawk">include.nawk</a></p>
<p>NAWK's getline can also read from a pipe. If you have a program that generates  single line, you can use</p>
<pre>"command" | getline;
 print $0;</pre>
<p>or</p>
<pre>"command" | getline abc;
 print abc;</pre>
<p>If you have more than one line, you can loop through the results:</p>
<pre>while ("command" | getline) {
cmd[i++] = $0;
}
for (i in cmd) {
printf("%s=%sn", i, cmd[i]);
}</pre>
<p>Only one pipe can be open at a time. If you want to open another pipe, you must execute</p>
<pre>close("command");</pre>
<p>This is necessary even if the end of file is reached.</p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-50" name="awk-50" title="The systime function" id="awk-50">The systime function</a></h2>
<p>The <em>systime</em>() function returns the current time of day as the number of seconds since Midnight, January 1, 1970. It is useful for measuring how long portions of your GAWK code takes to execute. </p>
<pre>#!/usr/local/bin/gawk -f
# how long does it take to do a few loops?
BEGIN {
LOOPS=100;
# do the test twice
start=systime();
for (i=0;i&lt;= 0) {
printf("%d loops were not enough to test, increase itn",
LOOPS);
exit;
} else {
printf("%d loops took %6.4f seconds to executen",
LOOPS, newtime);
printf("That&#039;s %10.8f seconds per loopn",
(newtime)/LOOPS);
# since the clock has an accuracy of +/- one second, what is the error
printf("accuracy of this measurement = %6.2f%%n",
(1/(newtime))*100);
}
exit;
}</pre>
<p> View file: <a href="http://static.askapache.com/shell-scripts/awk_example17.gawk">awk_example17.gawk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-51" name="awk-51" title="The Strftime function" id="awk-51">The Strftime function</a></h2>
<p>GAWK has a special function for creating strings based on the current time. It's based on the <em>strftime</em>(3c) function. If you are familiar with the  "+" formats of the <em>date</em>(1) command, you have a good head-start on understanding what the <em>strftime</em> command is used for. The <em>systime</em>() function returns the current date in seconds. Not very useful if you want to create a string based on the time. While you could convert the seconds into days, months, years, etc., it would be easier to execute "date" and pipe the results into a string. (See the previous script for an example). GAWK has another solution that eliminates the need for  an external program.</p>
<p>The function takes one or two arguments. The first argument is a string that specified the format. This string contains regular characters and special characters. Special characters start with a backslash or the percent character. The backslash characters with the backslash prefix are the same I covered earlier. In addition, the <em>strftime</em>() function defines dozens of combinations, all of which start with "%." The following table lists these special sequences:</p>
<pre>+---------------------------------------------------------------+
|        AWK Table 12        |
|        GAWK&#039;s strftime formats      |
+---------------------------------------------------------------+
|%a   The locale&#039;s abbreviated weekday name      |
|%A   The locale&#039;s full weekday name        |
|%b   The locale&#039;s abbreviated month name      |
|%B   The locale&#039;s full month name        |
|%c   The locale&#039;s "appropriate" date and time representation  |
|%d   The day of the month as a decimal number (01--31)    |
|%H   The hour (24-hour clock) as a decimal number (00--23)  |
|%I   The hour (12-hour clock) as a decimal number (01--12)  |
|%j   The day of the year as a decimal number (001--366)  |
|%m   The month as a decimal number (01--12)      |
|%M   The minute as a decimal number (00--59)      |
|%p   The locale&#039;s equivalent of the AM/PM      |
|%S   The second as a decimal number (00--61).      |
|%U   The week number of the year (Sunday is first day of week) |
|%w   The weekday as a decimal number (0--6).  Sunday is day 0  |
|%W   The week number of the year (Monday is first day of week) |
|%x   The locale&#039;s "appropriate" date representation    |
|%X   The locale&#039;s "appropriate" time representation    |
|%y   The year without century as a decimal number (00--99)  |
|%Y   The year with century as a decimal number      |
|%Z   The time zone name or abbreviation      |
|%%   A literal %.            |
+---------------------------------------------------------------+</pre>
<p>Depending on your operating system, and installation, you may also have the following formats:</p>
<pre>+-----------------------------------------------------------------------+
|            AWK Table 13        |
|         Optional GAWK strftime formats      |
+-----------------------------------------------------------------------+
|%D   Equivalent to specifying %m/%d/%y          |
|%e   The day of the month, padded with a blank if it is only one digit |
|%h   Equivalent to %b, above            |
|%n   A newline character (ASCII LF)          |
|%r   Equivalent to specifying %I:%M:%S %p        |
|%R   Equivalent to specifying %H:%M          |
|%T   Equivalent to specifying %H:%M:%S          |
|%t   A TAB character              |
|%k   The hour as a decimal number (0-23)        |
|%l   The hour (12-hour clock) as a decimal number (1-12)    |
|%C   The century, as a number between 00 and 99      |
|%u   is replaced by the weekday as a decimal number [Monday == 1]  |
|%V   is replaced by the week number of the year (using ISO 8601)  |
|%v   The date in VMS format (e.g. 20-JUN-1991)        |
+-----------------------------------------------------------------------+</pre>
<p>One useful format is</p>
<pre>strftime("%y_%m_%d_%H_%M_%S")</pre>
<p>This constructs a string that contains the year, month, day, hour, minute and second in a format that allows convenient sorting. If you ran this at noon on Christmas, 1994, it would generate the string</p>
<pre>94_12_25_12_00_00</pre>
<p>Here is the GAWK equivalent of the date command:
<pre>#! /usr/local/bin/gawk -f
 #
&nbsp;
 BEGIN {
 format = "%a %b %e %H:%M:%S %Z %Y";
 print strftime(format); }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/date.gawk">date.gawk</a></p>
<p>You will note that there is no exit command in the begin statement. If I was using AWK, an exit statement is necessary. Otherwise, it would never terminate. If there is no action defined for each line read, NAWK and GAWK do not need an exit statement.</p>
<p>If you provide a second argument to the <em>strftime</em>() function, it uses that argument as the timestamp, instead of the current system's time. This is useful for calculating future times. The following script calculates the time one week after the current time:
<pre>#!/usr/local/bin/gawk -f
 BEGIN {
 #  get current time
 ts = systime();
 # the time is in seconds, so
 one_day = 24 * 60 * 60;
 next_week = ts + (7 * one_day);
 format = "%a %b %e %H:%M:%S %Z %Y";
 print strftime(format, next_week);
 exit; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/one_week_later.gawk">one_week_later.gawk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-52" name="awk-52" title="User Defined Functions" id="awk-52">User Defined Functions</a></h2>
<p>Finally, NAWK and GAWK support user defined functions. This function demonstrates a way to print error messages, including the filename and line number, if appropriate:
<pre>#!/usr/bin/nawk -f
 {
 if (NF != 4) {
 error("Expected 4 fields");
 } else {
 print;
 }
 }
 function error ( message ) {
 if (FILENAME != "-") {
 printf("%s: ", FILENAME) &gt; "/dev/tty";
 }
 printf("line # %d, %s, line: %sn", NR, message, $0) &gt;&gt; "/dev/tty"; }</pre>
<p>View file: <a href="http://static.askapache.com/shell-scripts/awk_example18.nawk">awk_example18.nawk</a></p>





<h2><a href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-53" name="awk-53" title="AWK patterns" id="awk-53">AWK patterns</a></h2>
<p>&nbsp;</p>
<p>In my first tutorial on AWK, I described the AWK statement as having the form
<pre>pattern {commands}</pre>
<p>I have only used two patterns so far: the special words <em>BEGIN</em> and <em>END</em>. Other patterns are possible, yet I haven't used any. There are several reasons for this. The first is that these patterns aren't necessary. You can duplicate them using an <em>if</em> statement. Therefore this is an  "advanced feature." Patterns, or perhaps the better word is conditions, tend to make an AWK program obscure to a beginner. You can think of them as an  advanced topic, one that should be attempted after becoming familiar with  the basics.
<p>A pattern or condition is simply an abbreviated test. If the condition is true, the action is performed. All relational tests can be used as a pattern. The "tail -10" command, which prints the first 10 lines and stops, can be duplicated with
<pre>{if (NR &lt;= 10 ) {print}}</pre>
<p>Changing the <em>if</em> statement to a condition shortens the code:
<pre>NR &lt;= 10 {print}</pre>
<p>Besides relational tests, you can also use containment tests, i. e.  do strings contain regular expressions? Printing all lines that contain the word "special" can be written as
<pre>{if ($0 ~ /special/) {print}}</pre>
<p>or more briefly
<pre>$0 ~ /special/ {print}</pre>
<p>This type of test is so common, the authors of AWK allow a third, shorter format:
<pre>/special/ {print}</pre>
<p>These tests can be combined with the AND (<em>&amp;&amp;</em>) and OR (<em>||</em>) commands, as well as the NOT (<em>!</em>) operator. Parenthesis can also be added if you are in doubt, or to make your intention clear.
<p>The following condition prints the line if it contains the word "whole" or columns 1 and 2 contain "part1" and  "part2" respectively.
<pre>($0 ~ /whole/) || (($1 ~ /part1/) &amp;amp;&amp;amp; ($2 ~ /part2/)) {print}</pre>
<p>This can be shortened to
<pre>/whole/ || $1 ~ /part1/ &amp;amp;&amp;amp; $2 ~ /part2/ {print}</pre>
<p>There is one case where adding parenthesis hurts. The condition
<pre>/whole/ {print}</pre>
<p>works, but
<pre>(/whole/) {print}</pre>
<p>does not. If parenthesis are used, it is necessary to explicitly specify the test:
<pre>($0 ~ /whole) {print}</pre>
<p>A murky situation arises when a simple variable is used as a condition. Since the variable <em>NF</em> specifies the number of fields on a line, one might think the statement
<pre>NF {print}</pre>
<p>would print all lines with one of more fields. This is an illegal command for AWK, because AWK does not accept variables as conditions. To prevent a syntax error, I had to change it to
<pre>NF != 0 {print}</pre>
<p>I expected NAWK to work, but on some SunOS systems it refused to print any lines at all. On newer Solaris systems it did behave properly. Again, changing it to the longer form worked for all variations. GAWK, like the newer version of NAWK, worked properly. After this experience, I decided to leave other, exotic variations alone. Clearly this is unexplored territory.  I could write a script that prints the first 20 lines, except if there  were exactly three fields, unless it was line 10, by using
<pre>NF == 3 ? NR == 10 : NR &lt; 20 { print }</pre>
<p>But I won't. Obscurity, like puns, is often unappreciated.
<p>There is one more common and useful pattern I have not yet described. It is the comma separated pattern. A common example has the form:
<pre>/start/,/stop/ {print}</pre>
<p>This form defines, in one line, the condition to turn the action on, and the condition to turn the action off. That is, when a line containing "start" is seen, it is printed. Every line afterwards is also printed, until a line containing "stop" is seen. This one is also printed, but the line after, and all following lines, are not printed. This triggering on and off can be repeated many times. The equivalent code, using the <em>if</em> command, is:
<pre>{
 if ($0 ~ /start/) {
 triggered=1;
 }
 if (triggered) {
 print;
 if ($0 ~ /stop/) {
 triggered=0;
 }
 }
 }</pre>
<p>The conditions do not have to be regular expressions. Relational tests can also be used. The following prints all lines between 20 and 40:
<pre>(NR==20),(NR==40) {print}</pre>
<p>You can mix relational and containment tests. The following prints every line until a "stop" is seen:
<pre>(NR==1),/stop/ {print}</pre>
<p>There is one more area of confusion about patterns: each one is independent of the others. You can have several patterns in a script; none influence the other patterns. If the following script is executed:
<pre>NR==10 {print}
 (NR==5),(NR==15) {print}
 /xxx/ {print}
 (NR==1),/NeVerMatchThiS/ {print}</pre>
<p>and the input file's line 10 contains "xxx," it would be printed 4 times, as each condition is true.  You can think of each condition as cumulative. The exception is the special <strong>BEGIN</strong> and <strong>END</strong> conditions. In the original AWK, you can only have one of each. In NAWK and GAWK, you can have several BEGIN or END actions.





<h2><a name="awk-54" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-54" title="Formatting AWK programs">Formatting AWK programs</a></h2>
<p>Many readers have questions my style of AWK programming. In particular, they ask me why I include code like this:
<pre># Print column 3
 print $3;</pre>
<p>when I could use
<pre>print $3 # print column 3</pre>
<p>After all, they reason, the semicolon is unnecessary,  and comments do not have to start on the first column. This is true. Still I avoid this. Years ago, when I started writing AWK programs, I would find myself confused when the nesting of conditions were too deep. If I moved a complex <em>if</em> statement inside another <em>if</em> statement, my alignment of braces became incorrect. It can be very difficult to repair this condition, especially with large  scripts. Nowadays I use <em>emacs</em> to do the formatting for me, but 10 years ago I didn't have this option. My solution was to use the program <em>cb</em>, which is a  "C beautifier." By including optional semicolons, and starting comments on the first column of the line, I could send my AWK script through this filter, and  properly align all of the code.





<h2><a name="awk-55" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-55" title="Environment Variables">Environment Variables</a></h2>
<p>I've described the 7 special  variables in AWK, and briefly mentioned some others NAWK and GAWK. The complete list follows:
<pre>+--------------------------------+
|         AWK Table 14        |
|Variable      AWK    NAWK   GAWK |
+--------------------------------+
|FS      Yes    Yes   Yes  |
|NF      Yes    Yes   Yes  |
|RS      Yes    Yes   Yes  |
|NR      Yes    Yes   Yes  |
|FILENAME      Yes    Yes   Yes  |
|OFS      Yes    Yes   Yes  |
|ORS      Yes    Yes   Yes  |
+--------------------------------+
|ARGC      Yes   Yes  |
|ARGV      Yes   Yes  |
|ARGIND       Yes  |
|FNR      Yes   Yes  |
|OFMT      Yes   Yes  |
|RSTART      Yes   Yes  |
|RLENGTH      Yes   Yes  |
|SUBSEP      Yes   Yes  |
|ENVIRON       Yes  |
|IGNORECASE     Yes  |
|CONVFMT       Yes  |
|ERRNO       Yes  |
|FIELDWIDTHS     Yes  |
+--------------------------------+</pre>
<p>Since I've already discussed many of these, I'll only cover those that I missed earlier.





<h2><a name="awk-56" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-56" title="ARGC - Number or arguments (NAWK/GAWK)">ARGC - Number or arguments (NAWK/GAWK)</a></h2>
<p>The variable <strong>ARGC</strong> specifies the number of arguments on the command line. It always has the value of one or more, as it counts its own program name as the first argument. If you specify an AWK filename using the "-f" option, it is not counted as an argument. If you include a variable on the command line using the form below,  NAWK does not count as an argument.
<pre>nawk -f file.awk x=17</pre>
<p>GAWK does, but that is because GAWK requires the  "-v" option before each assignment:
<pre>gawk -f file.awk -v x=17</pre>
<p>GAWK variables initialized this way do not affect the <strong>ARGC</strong> variable.





<h2><a name="awk-57" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-57" title="ARGV - Array of arguments (NAWK/GAWK)">ARGV - Array of arguments (NAWK/GAWK)</a></h2>
<p>The <strong>ARGV</strong> array is the list of arguments (or files) passed as command line arguments.





<h2><a name="awk-58" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-58" title="ARGIND - Argument Index (GAWK only)">ARGIND - Argument Index (GAWK only)</a></h2>
<p>The <strong>ARGIND</strong> specifies the current index into the <strong>ARGV</strong> array, and therefore <strong>ARGV[ARGIND]</strong> is always the current filename. Therefore
<pre>FILENAME == ARGV[ARGIND]</pre>
<p>is always true. It can be modified, allowing you to skip over files, etc.





<h2><a name="awk-59" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-59" title="FNR (NAWK/GAWK)">FNR (NAWK/GAWK)</a></h2>
<p>The <strong>FNR</strong> variable contains the number of lines read, but is reset for each file read. The <strong>NR</strong> variable accumulates for all files read. Therefore if you execute an awk script with two files as arguments, with each containing 10 lines:
<pre>nawk &#039;{print NR}&#039; file file2
 nawk &#039;{print FNR}&#039; file file2</pre>
<p>the first program would print the numbers 1 through 20, while the second would print the numbers 1 through 10 twice, once for each file.





<h2><a name="awk-60" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-60" title="OFMT (NAWK/GAWK)">OFMT (NAWK/GAWK)</a></h2>
<p>The <strong>OFMT</strong> variable Specifies the default format for numbers. The default value is "%.6g."





<h2><a name="awk-61" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-61" title="RSTART, RLENGTH and match (NAWK/GAWK)">RSTART, RLENGTH and match (NAWK/GAWK)</a></h2>
<p>I've already mentioned the <strong>RSTART</strong> and <strong>RLENGTH</strong> variables. After the <em>match</em>() function is called, these variables contain the location in the string  of the search pattern. <strong>RLENGTH</strong> contains the length of this match.





<h2><a name="awk-62" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-62" title="SUBSEP - Multi-dimensional array separator (NAWK/GAWK)">SUBSEP - Multi-dimensional array separator (NAWK/GAWK)</a></h2>
<p>Earlier I described how you can construct multi-dimensional arrays in AWK. These are constructed by concatenating two indexes together with a special character between them. If I use an ampersand as the special character, I can access the value at location X, Y by the reference
<pre>array[ X "&amp;amp;" Y ]</pre>
<p>NAWK (and GAWK) has this feature built in. That is, you can specify the array element
<pre>array[X,Y]</pre>
<p>It automatically constructs the string, placing a special character between the indexes. This character is the non-printing character "034." You can control the value of this character, to make sure your  strings do not contain the same character.





<h2><a name="awk-63" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-63" title="ENVIRON - environment variables (GAWK only)">ENVIRON - environment variables (GAWK only)</a></h2>
<p>The <strong>ENVIRON</strong> array contains the environment variables the current process. You can print your current search path using
<pre>print ENVIRON["PATH"]</pre>





<h2><a name="awk-64" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-64" title="IGNORECASE (GAWK only)">IGNORECASE (GAWK only)</a></h2>
<p>The <strong>IGNORECASE</strong> variable is normally zero. If you set it to non-zero, then all pattern matches ignore case. Therefore the following is equivalent to  "grep -i match:"
<pre>BEGIN {IGNORECASE=1;}
 /match/ {print}</pre>





<h2><a name="awk-65" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-65" title="CONVFMT - conversion format (GAWK only)">CONVFMT - conversion format (GAWK only)</a></h2>
<p>The <strong>CONVFMT</strong> variable is used to specify the format when converting a number to a string. The default value is "%.6g." One way to truncate integers is to convert an integer to a string, and convert the string to an integer - modifying the actions with <strong>CONVFMT</strong>:
<pre>a = 12;
 b = a "";
 CONVFMT = "%2.2f";
 c = a "";</pre>
<p>Variables <strong>b</strong> and <strong>c</strong> are both strings, but the first one will have the value "12.00" while the second will have the value "12."





<h2><a name="awk-66" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-66" title="ERRNO - system errors (GAWK only)">ERRNO - system errors (GAWK only)</a></h2>
<p>The <strong>ERRNO</strong> variable describes the error, as a string, after a call to the <strong>getline</strong> command fails.





<h2><a name="awk-67" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-67" title="FIELDWIDTHS - fixed width fields (GAWK only)">FIELDWIDTHS - fixed width fields (GAWK only)</a></h2>
<p>The <strong>FIELDWIDTHS</strong> variable is used when processing fixed width input. If you wanted to read a file that had 3 columns of data; the first one  is 5 characters wide, the second 4, and the third 7, you could use <em>substr</em> to split the line apart. The technique, using <strong>FIELDWIDTHS</strong>, would be:
<pre>BEGIN {FIELDWIDTHS="5 4 7";}
 { printf("The three fields are %s %s %sn", $1, $2, $3);}</pre>





<h2><a name="awk-68" href="http://www.askapache.com/awk/awk-tutorial.html#toc-awk-68" title="AWK, NAWK, GAWK, or PERL">AWK, NAWK, GAWK, or PERL</a></h2>
<p>This concludes my series of tutorials on AWK and the NAWK and GAWK variants. I originally intended to avoid extensive coverage of NAWK and GAWK. I am a PERL user myself, and still believe PERL is worth learning, yet I don't intend to cover this very complex language. Understanding AWK is very useful when you start to learn PERL, and a part of me felt that teaching you extensive NAWK and GAWK features might encourage you to bypass PERL.
<p>I found myself going into more depth than I planned, and I hope you found this useful. I found out a lot myself, especially when I discussed topics not covered in other books. Which reminds me of some closing advice: if you don't understand how something works, experiment and see what you can discover. Good luck, and happy AWKing...
<p> Other of my Unix shell tutorials can be found <a href="http://www.grymoire.com/Unix">here.</a> Other shell tutorials can be found at <a href="http://www.shelldorado.com/links/index.html#tutorials">Heiner's SHELLdorado</a> and <a href="http://cfaj.freeshell.org/shell/">Chris F. A. Johnson's Unix Shell Page</a> <em>This document was translated by troff2html v0.21 on September 22, 2001 and then manually edited to make it compliant with:</em> <a href="http://validator.w3.org/check?uri=referer"><img src="http://www.w3.org/Icons/valid-html401" alt="Valid HTML 4.01!" height="31" width="88" title=" linux" /></a></p><p><a href="http://www.askapache.com/linux/awk-tutorial.html"></a><a href="http://www.askapache.com/linux/awk-tutorial.html">Awk Tutorial and Introduction</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/linux/awk-tutorial.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Links to htaccess tutorials and articles</title>
		<link>http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html</link>
		<comments>http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html#comments</comments>
		<pubDate>Thu, 09 Nov 2006 01:58:45 +0000</pubDate>
		<dc:creator>AskApache</dc:creator>
				<category><![CDATA[Htaccess]]></category>

		<guid isPermaLink="false">http://www.askapache.com.com/htaccess-forum/best-htaccess-tutorials-and-articles.html</guid>
		<description><![CDATA[<p>Links to htaccess tutorials and howtos in the <a href="http://www.htaccesselite.com">htaccess forum</a></p>]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html"></a><a href="http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html"><cite>AskApache.com</cite></a></p><p>Links to htaccess tutorials and howtos in the <a href="http://www.htaccesselite.com">htaccess forum</a></p>
<hr />
<ul>
    <li><a href="http://www.htaccesselite.com/addtype-to-run-htm-as-php-vt7.html">AddType to run .htm as .php</a></li>
    <li><a href="http://www.htaccesselite.com/apache-mod-rewrite-technical-details-vt95.html">Apache mod_rewrite Technical Details</a></li>
    <li><a href="http://www.htaccesselite.com/azdg-script-shorten-url-with-mod-rewrite-vt57.html">azdg script - shorten url with mod rewrite</a></li>
    <li><a href="http://www.htaccesselite.com/basic-authentication-example-vt17.html">Basic authentication example</a></li>
    <li><a href="http://www.htaccesselite.com/block-everyone-except-1-ip-address-vt43.html">Block everyone except 1 IP Address</a></li>
    <li><a href="http://www.htaccesselite.com/cache-control-http-headers-vt65.html">Cache-Control HTTP Headers</a></li>
    <li><a href="http://www.htaccesselite.com/caching-and-optimization-vf1.html">View Forum - Caching and Optimization</a></li>
    <li><a href="http://www.htaccesselite.com/caching-using-header-vt2.html">Caching using header</a></li>
    <li><a href="http://www.htaccesselite.com/caching-using-mod-expires-with-expires-vt5.html">Caching Using mod_expires with expires</a></li>
    <li><a href="http://www.htaccesselite.com/cname-to-a-diffrent-folder-using-the-htaccess-vt76.html">cname to a diffrent folder using the htaccess</a></li>
    <li><a href="http://www.htaccesselite.com/commonly-used-htaccess-code-examples-vt119.html">Commonly Used htaccess Code examples</a></li>
    <li><a href="http://www.htaccesselite.com/create-hyperlinks-to-switch-between-http-and-https-vt60.html">Create hyperlinks to switch between HTTP and HTTPS</a></li>
    <li><a href="http://www.htaccesselite.com/creating-etag-headers-in-php-vt112.html">Creating ETag headers in php</a></li>
    <li><a href="http://www.htaccesselite.com/creating-seo-friendly-url-redirector-vt53.html">Creating SEO Friendly URL redirector</a></li>
    <li><a href="http://www.htaccesselite.com/debugging-php-vt26.html">Debugging PHP</a></li>
    <li><a href="http://www.htaccesselite.com/deny-a-block-of-ip-addresses-vt41.html">Deny a Block of IP Addresses</a></li>
    <li><a href="http://www.htaccesselite.com/deny-a-user-based-on-their-ip-address-vt40.html">Deny A User based on their IP address</a></li>
    <li><a href="http://www.htaccesselite.com/deny-access-to-a-folder-based-on-the-time-vt44.html">Deny access to a folder based on the Time</a></li>
    <li><a href="http://www.htaccesselite.com/deny-based-on-domain-name-vt42.html">Deny based on domain name</a></li>
    <li><a href="http://www.htaccesselite.com/difference-between-php-cgi-and-php-as-an-apache-module-vt106.html">Difference between PHP-CGI and PHP as an Apache module</a></li>
    <li><a href="http://www.htaccesselite.com/directoryindex-can-point-to-external-page-also-vt13.html">DirectoryIndex can point to external page also</a></li>
    <li><a href="http://www.htaccesselite.com/disable-directory-listings-vt39.html">Disable Directory Listings</a></li>
    <li><a href="http://www.htaccesselite.com/does-htaccess-go-in-root-or-htdocs-vt32.html">Does .htaccess go in root or htdocs?</a></li>
    <li><a href="http://www.htaccesselite.com/dont-cache-page-vt113.html">Dont-cache Page</a></li>
    <li><a href="http://www.htaccesselite.com/dynamic-mirror-vt98.html">Dynamic Mirror</a></li>
    <li><a href="http://www.htaccesselite.com/environment-variables-in-apache-vt100.html">Environment Variables in Apache</a></li>
    <li><a href="http://www.htaccesselite.com/errordocument-example-vt11.html">ErrorDocument Example</a></li>
    <li><a href="http://www.htaccesselite.com/etags-vt68.html">Etags</a></li>
    <li><a href="http://www.htaccesselite.com/force-files-to-download-not-be-displayed-in-browser-vt47.html">Force Files to download, not be displayed in browser</a></li>
    <li><a href="http://www.htaccesselite.com/force-https-and-no-double-login-vt30.html">FORCE HTTPS AND NO DOUBLE LOGIN</a></li>
    <li><a href="http://www.htaccesselite.com/from-old-to-new-extern-vt93.html">From Old to New (extern)</a></li>
    <li><a href="http://www.htaccesselite.com/from-static-to-dynamic-vt94.html">From Static to Dynamic</a></li>
    <li><a href="http://www.htaccesselite.com/google-cheat-sheet-vt80.html">Google Cheat Sheet</a></li>
    <li><a href="http://www.htaccesselite.com/google-webmasters-blog-vt78.html">Google Webmasters Blog</a></li>
    <li><a href="http://www.htaccesselite.com/here-are-a-few-examples-of-some-redirects-vt45.html">Here are a few examples of some redirects:</a></li>
    <li><a href="http://www.htaccesselite.com/howto-debug-headers-vt28.html">HowTo Debug Headers</a></li>
    <li><a href="http://www.htaccesselite.com/htaccess-files-useful-tips-and-tricks-vt103.html">HTACCESS files useful tips and tricks</a></li>
    <li><a href="http://www.htaccesselite.com/htaccess-to-secure-a-public-directory-vt24.html">Htaccess to Secure a Public Directory</a></li>
    <li><a href="http://www.htaccesselite.com/i-want-to-create-a-virtual-hosting-situation-vt74.html">I want to create a &#39;virtual hosting&#39; situation</a></li>
    <li><a href="http://www.htaccesselite.com/inside-google-sitemaps-improving-your-site-s-indexing-and-r-vt79.html">Inside Google Sitemaps: Improving your site&#39;s indexing and r</a></li>
    <li><a href="http://www.htaccesselite.com/limit-the-number-of-concurrent-visitors-to-your-website-vt38.html">Limit the Number of Concurrent Visitors to your Website</a></li>
    <li><a href="http://www.htaccesselite.com/load-balancing-vt99.html">Load Balancing</a></li>
    <li><a href="http://www.htaccesselite.com/main-vf13.html">View Forum - Main</a></li>
    <li><a href="http://www.htaccesselite.com/misc-notes-about-security-401-etc-vt55.html">Misc Notes about Security/401/etc</a></li>
    <li><a href="http://www.htaccesselite.com/missing-trailing-slash-code-vt23.html">Missing Trailing Slash Code</a></li>
    <li><a href="http://www.htaccesselite.com/mod-rewrite-efficiency-question-vt27.html">mod_rewrite Efficiency Question</a></li>
    <li><a href="http://www.htaccesselite.com/mod-rewrite-flags-vt101.html">Mod_Rewrite Flags</a></li>
    <li><a href="http://www.htaccesselite.com/more-on-php5-fcgi-setup-vt108.html">More on php5.fcgi setup</a></li>
    <li><a href="http://www.htaccesselite.com/most-searched-for-words-in-phpbb-vt109.html">Most searched for words in phpbb</a></li>
    <li><a href="http://www.htaccesselite.com/move-homedirs-to-different-webserverdescription-vt86.html">Move Homedirs to Different WebserverDescription:</a></li>
    <li><a href="http://www.htaccesselite.com/moved-documentroot-vt85.html">Moved DocumentRoot</a></li>
    <li><a href="http://www.htaccesselite.com/multiple-custom-php-ini-vt25.html">Multiple Custom PHP.ini</a></li>
    <li><a href="http://www.htaccesselite.com/multple-domains-using-htaccess-vt72.html">Multple domains using htaccess</a></li>
    <li><a href="http://www.htaccesselite.com/newbie-htaccess-tutorial-vt105.html">Newbie htaccess Tutorial</a></li>
    <li><a href="http://www.htaccesselite.com/on-page-load-vt110.html">On Page Load</a></li>
    <li><a href="http://www.htaccesselite.com/optimizing-phpbb-for-seo-vt118.html">Optimizing PHPBB for SEO</a></li>
    <li><a href="http://www.htaccesselite.com/order-allow-deny-vt54.html">Order, Allow, Deny</a></li>
    <li><a href="http://www.htaccesselite.com/password-protection-not-working-right-vt31.html">Password Protection not working right</a></li>
    <li><a href="http://www.htaccesselite.com/permanently-renaming-a-file-or-directory-vt51.html">Permanently renaming a file or directory</a></li>
    <li><a href="http://www.htaccesselite.com/php-cgi-vs-mod-php-vt58.html">php-cgi vs mod_php</a></li>
    <li><a href="http://www.htaccesselite.com/php-security-vt107.html">PHP Security</a></li>
    <li><a href="http://www.htaccesselite.com/php-session-id-use-for-seo-vt114.html">PHP Session ID use for SEO</a></li>
    <li><a href="http://www.htaccesselite.com/prevent-image-hotlinking-vt48.html">Prevent Image HotLinking</a></li>
    <li><a href="http://www.htaccesselite.com/problem-with-cms-stats-vt70.html">Problem with CMS/Stats</a></li>
    <li><a href="http://www.htaccesselite.com/processing-all-gif-images-through-a-cgi-script-vt59.html">Processing all GIF images through a CGI script</a></li>
    <li><a href="http://www.htaccesselite.com/protect-an-entire-directory-vt36.html">Protect an entire directory</a></li>
    <li><a href="http://www.htaccesselite.com/protect-multiple-specific-files-vt18.html">Protect multiple specific files</a></li>
    <li><a href="http://www.htaccesselite.com/protect-single-file-vt37.html">Protect single File</a></li>
    <li><a href="http://www.htaccesselite.com/protect-your-htaccess-file-vt46.html">Protect your htaccess file</a></li>
    <li><a href="http://www.htaccesselite.com/quoting-special-characters-vt102.html">Quoting Special Characters</a></li>
    <li><a href="http://www.htaccesselite.com/re-direct-any-requests-that-are-not-files-or-dirs-vt52.html">re-direct any requests that are not files or dirs</a></li>
    <li><a href="http://www.htaccesselite.com/redirect-contact-to-contact-php-vt33.html">Redirect /contact/ to /contact.php</a></li>
    <li><a href="http://www.htaccesselite.com/redirect-failing-urls-to-other-webserver-vt97.html">Redirect Failing URLs To Other Webserver</a></li>
    <li><a href="http://www.htaccesselite.com/redirecting-all-or-part-of-a-server-to-ssl-vt61.html">Redirecting All or Part of a Server to SSL</a></li>
    <li><a href="http://www.htaccesselite.com/redirecting-anchors-vt90.html">Redirecting Anchors</a></li>
    <li><a href="http://www.htaccesselite.com/redirectmatch-redirectpermanent-redirecttemp-vt62.html">RedirectMatch RedirectPermanent RedirectTemp</a></li>
    <li><a href="http://www.htaccesselite.com/regular-expressions-in-dreamweaver-vt111.html">Regular Expressions in Dreamweaver</a></li>
    <li><a href="http://www.htaccesselite.com/rel-link-types-vt69.html">rel Link types</a></li>
    <li><a href="http://www.htaccesselite.com/require-ssl-before-asking-for-htaccess-password-vt12.html">Require SSL before asking for htaccess password!</a></li>
    <li><a href="http://www.htaccesselite.com/requiring-the-www-vt6.html">Requiring the WWW</a></li>
    <li><a href="http://www.htaccesselite.com/rewrite-contact-to-cgi-bin-contact-php-vt56.html">Rewrite /contact/ to /cgi-bin/contact.php?</a></li>
    <li><a href="http://www.htaccesselite.com/rewrite-old-to-new-internally-vt92.html">Rewrite old to new internally</a></li>
    <li><a href="http://www.htaccesselite.com/rewrite-requests-for-s-file-spl-to-cgi-bin-file-php-vt20.html">Rewrite requests for /s/file.spl to /cgi-bin/file.php</a></li>
    <li><a href="http://www.htaccesselite.com/rewritecond-vt64.html">RewriteCond</a></li>
    <li><a href="http://www.htaccesselite.com/robots-meta-tag-and-googlebot-vt117.html">Robots meta tag and googlebot</a></li>
    <li><a href="http://www.htaccesselite.com/sample-htaccess-vt75.html">Sample htaccess</a></li>
    <li><a href="http://www.htaccesselite.com/search-for-files-vt87.html">Search for files [in more than one directory]</a></li>
    <li><a href="http://www.htaccesselite.com/security-vf5.html">View Forum - Security</a></li>
    <li><a href="http://www.htaccesselite.com/seo-friendly-urls-for-php-vt34.html">SEO Friendly URLs for PHP</a></li>
    <li><a href="http://www.htaccesselite.com/serve-virtual-hosts-vt96.html">serve virtual hosts</a></li>
    <li><a href="http://www.htaccesselite.com/set-environment-variables-according-to-url-vt88.html">Set Environment Variables According To URL</a></li>
    <li><a href="http://www.htaccesselite.com/setenv-passenv-unsetenv-vf8.html">View Forum - SetEnv, PassEnv, UnsetEnv</a></li>
    <li><a href="http://www.htaccesselite.com/setenv-to-set-the-server-administrator-email-vt16.html">SetEnv to set the server administrator email</a></li>
    <li><a href="http://www.htaccesselite.com/setenv-to-set-the-server-timezone-vt15.html">SetEnv to set the server timezone</a></li>
    <li><a href="http://www.htaccesselite.com/setenv-to-specify-cgi-apache-error-log-vt50.html">SetEnv to Specify CGI/Apache Error Log</a></li>
    <li><a href="http://www.htaccesselite.com/setting-charset-information-in-htaccess-vt81.html">Setting charset information in .htaccess</a></li>
    <li><a href="http://www.htaccesselite.com/shell-scripts-vf25.html">View Forum - Shell Scripts</a></li>
    <li><a href="http://www.htaccesselite.com/some-basic-defaults-vt21.html">Some Basic Defaults</a></li>
    <li><a href="http://www.htaccesselite.com/some-good-default-addtypes-for-favicon-ico-and-flash-vt19.html">Some good default AddTypes for favicon.ico and flash</a></li>
    <li><a href="http://www.htaccesselite.com/specify-a-custom-error-document-vt49.html">Specify A Custom Error Document</a></li>
    <li><a href="http://www.htaccesselite.com/sql-vf27.html">View Forum - SQL</a></li>
    <li><a href="http://www.htaccesselite.com/ssl-vf3.html">View Forum - SSL</a></li>
    <li><a href="http://www.htaccesselite.com/status-codes-vt63.html">Status Codes</a></li>
    <li><a href="http://www.htaccesselite.com/stop-hotlinking-and-bandwidth-theft-vt104.html">[How Do I] Stop Hotlinking and Bandwidth Theft?</a></li>
    <li><a href="http://www.htaccesselite.com/switch-php-between-running-as-a-cgi-and-an-apache-module-vt10.html">Switch PHP between running as a CGI and an Apache module</a></li>
    <li><a href="http://www.htaccesselite.com/the-7-link-types-vt83.html">The 7 Link Types</a></li>
    <li><a href="http://www.htaccesselite.com/this-piece-of-code-returns-a-blank-gif-vt71.html">This piece of code returns a blank gif</a></li>
    <li><a href="http://www.htaccesselite.com/time-dependent-rewriting-vt91.html">Time-Dependent Rewriting</a></li>
    <li><a href="http://www.htaccesselite.com/use-htaccess-to-speed-up-your-site-discussion-vt67.html">Use htaccess to speed up your site discussion</a></li>
    <li><a href="http://www.htaccesselite.com/useing-redirectmatch-to-redirect-using-regexp-vt35.html">Useing RedirectMatch to redirect using regexp</a></li>
    <li><a href="http://www.htaccesselite.com/using-defaultcharset-and-defaultlanguage-to-eliminate-meta-vt22.html">Using defaultcharset and defaultlanguage to eliminate meta</a></li>
    <li><a href="http://www.htaccesselite.com/using-filesmatch-to-target-files-vt9.html">Using FilesMatch to target files</a></li>
    <li><a href="http://www.htaccesselite.com/using-htaccess-redirection-to-standardize-web-server-addres-vt73.html">Using .htaccess Redirection to Standardize Web Server Addres</a></li>
    <li><a href="http://www.htaccesselite.com/using-html-instead-of-php-vt82.html">Using .html instead of .php</a></li>
    <li><a href="http://www.htaccesselite.com/using-php-to-force-a-download-vt29.html">Using PHP to force a download?</a></li>
    <li><a href="http://www.htaccesselite.com/using-php-to-force-a-download-vt66.html">Using PHP to force a download</a></li>
    <li><a href="http://www.htaccesselite.com/using-setenv-to-instruct-php-to-use-custom-php-ini-vt14.html">Using SetEnv to instruct php to use custom php.ini</a></li>
    <li><a href="http://www.htaccesselite.com/virtual-user-hosts-vt89.html">Virtual User Hosts [using HTTP_HOST header]</a></li>
    <li><a href="http://www.htaccesselite.com/wikipedias-htaccess-page-vt77.html">Wikipedias Htaccess Page</a></li>
</ul><p><a href="http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html"></a><a href="http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html">Links to htaccess tutorials and articles</a> originally appeared on <cite>AskApache.com</cite> </p>]]></content:encoded>
			<wfw:commentRss>http://www.askapache.com/htaccess/best-htaccess-tutorials-and-articles.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

