<?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>Pario TechnoBlob &#187; basename</title>
	<atom:link href="http://pario.no/tag/basename/feed/" rel="self" type="application/rss+xml" />
	<link>http://pario.no</link>
	<description>A cronological documentation test project, nothing serious, really!</description>
	<lastBuildDate>Thu, 02 Feb 2012 13:17:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>File Rename By File Extension</title>
		<link>http://pario.no/2007/11/18/file-rename-by-file-extension/</link>
		<comments>http://pario.no/2007/11/18/file-rename-by-file-extension/#comments</comments>
		<pubDate>Sun, 18 Nov 2007 19:27:15 +0000</pubDate>
		<dc:creator>Hans-Henry Jakobsen</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[basename]]></category>
		<category><![CDATA[bash]]></category>

		<guid isPermaLink="false">http://pario.no/2007/11/18/file-rename-by-file-extension/</guid>
		<description><![CDATA[for file in *htm ; do mv $file `basename $file htm`html; done"]]></description>
			<content:encoded><![CDATA[<pre>
for file in *htm ; do mv $file `basename $file htm`html; done"</pre>
<script type="text/javascript">var wordpress_toolbar_urls = [];var wordpress_toolbar_url = "http://pario.no/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "n";var wordpress_toolbar_hash = "aHR0cDovL3BhcmlvLm5vLzIwMDcvMTEvMTgvZmlsZS1yZW5hbWUtYnktZmlsZS1leHRlbnNpb24vPHdwdGI%2BRmlsZSBSZW5hbWUgQnkgRmlsZSBFeHRlbnNpb248d3B0Yj5odHRwOi8vcGFyaW8ubm88d3B0Yj5QYXJpbyBUZWNobm9CbG9i";</script>]]></content:encoded>
			<wfw:commentRss>http://pario.no/2007/11/18/file-rename-by-file-extension/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hints and Tips for general shell script programming</title>
		<link>http://pario.no/2007/08/31/hints-and-tips-for-general-shell-script-programing/</link>
		<comments>http://pario.no/2007/08/31/hints-and-tips-for-general-shell-script-programing/#comments</comments>
		<pubDate>Fri, 31 Aug 2007 18:14:36 +0000</pubDate>
		<dc:creator>Hans-Henry Jakobsen</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[awk]]></category>
		<category><![CDATA[basename]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[mailx]]></category>
		<category><![CDATA[nawk]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[sed]]></category>

		<guid isPermaLink="false">http://hhj.no/wordpress/2007/08/31/hints-and-tips-for-general-shell-script-programing/</guid>
		<description><![CDATA[WARNING: this will fail if the user is playing with $0 For example using a symbolic or hard link with a unexpected name. # Simplest... # PROGNAME=`type $0 &#124; awk '{print $3}'` # search for executable on path PROGNAME=`basename $PROGNAME` # base name of program # Advanced... # Script name, in what directory, and in [...]]]></description>
			<content:encoded><![CDATA[<p>WARNING: this will fail if the user is playing with $0<br />
For example using a symbolic or hard link with a unexpected name.</p>
<pre>
# Simplest...
#
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGNAME=`basename $PROGNAME`          # base name of program

# Advanced...
# Script name, in what directory, and in what directory is user
# running the script from.
#
# Discover where the shell script resides
ORIGDIR=`pwd`                          # original directory (builtin)
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
cd $PROGDIR                            # go to that directory
PROGDIR=`pwd`                          # remove any symbolic link parts
cd $ORIGDIR                            # return to original directory (opt)

<strong>Results...</strong>
   $ORIGDIR    -- where the users was when called
   $PROGDIR    -- script directory location (and now current directory)
   $PROGNAME   -- This scripts executable name</pre>
<p><strong>Shell Script Option Handling</strong></p>
<pre>
PROGNAME=`basename $0`   # Or the above script locator
Usage() {
  echo &gt;&amp;2 "$PROGNAME:" "$@"
  echo &gt;&amp;2 "Usage: $PROGNAME [options] [file...]"
  exit 10
}</pre>
<pre>
#!/bin/sh
#
# script [options] args...
#
# The frist 'Usage()' code that follows these comments locates the script on
# disk, and then reads and output these comments as the documentation for this
# script.   That is the script commands and usage documention are in the same
# file, making it self documenting, via options.
#
###
#
#  programmers only docs, whcih are not output by Usage()
#
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
Usage() {                              # output the script comments as docs
  echo &gt;&amp;2 "$PROGNAME:" "$@"
  sed &gt;&amp;2 -n '/^###/q; /^#/!q; s/^#//; s/^ //; 3s/^/Usage: /; 2,$ p'
          "$PROGDIR/$PROGNAME"
  exit 10;

#  Generalized Otion handling.
#
while [  $# -gt 0 ]; do
  case "$1" in

  # Standard help option.
  --help|--doc*) Usage ;;

  # Simple flag option
  -d) DEBUG=true ;;

  # Word flag option
  -debug) DEBUG=true ;;

  # Simple option and argument   EG: -n name
  -n) shift; name="$1" ;;

  # Option and argument joined   EG: -Jname
  -J) name=expr "$1" : '-.(.*)'` ||
            Usage "Option \"$1\" missing required value" ;;

  # Joined OR unjoined Argument  EG:  -Nname  or  -N name
  -N*) Name=`expr "$1" : '-.(..*)'`  || { shift; Name="$1"; } ;;

  # As last,  but if  -b0  is an posibility then you need to use this instead.
  # Otherwise it will think the value is unjoined when it isn't  Arrrgghhhh...
  -b*) bits=`expr "$1" : '-.(..*)'`
       [ "$bits" ] || { shift; bits="$1"; }
       ;;

  # Numbers with type checks     EG:  -{width}x{height}
  -[0-9]*x[0-9]*)
      w=`expr "$1" : '-([0-9]*)x'`          || Usage "Bed Geometry"
      h=`expr "$1" : '-[0-9]*x([0-9]*)$'`   || Usage "Bad Geometry"
      [ "$width" -eq 0  -o  "$height" -eq 0 ] &amp;&amp; Usage "Zero Geometry"
      geometry="${w}x${h}"
      ;;

  # Number with type check     EG:  -{size}
  -[0-9]*)
      size=`expr "$1" : '-([0-9]*)$'`  ||  Usage
      [ "$size" -eq 0 ] &amp;&amp; Usage
      Width=$size; Height=$size
      ;;

  # Generalised Argument Save    EG:    -G value  =&gt;  $opt_G
  -*) var=`expr "$1" : '-(.).*'`
      case "$var" in
      [a-zA-Z]) arg=`expr "$1" : '-.(..*)'`  ||  { shift; arg="$1"; }
                eval "opt_$var"="\"$arg\"" ;;
      *) Usage "Bad Non-Letter option \"$1\"" ;;
      esac ;;

  -)  break ;;           # STDIN,  end of user options

  --) shift; break ;;    # end of user options
  -*) Usage "Unknown option \"$1\"" ;;
  *)  break ;;           # end of user options

  esac
  shift   # next option
done

# Handle normal arguments now...
Files=${1+"$@"}

# or
[ $# -gt 0 ] &amp;&amp; Usage "To many Arguments"</pre>
<p><strong>Variable testing under shell (rules of thumb)</strong></p>
<p>Boolean Variable tests&#8230;</p>
<pre>
     true="true";   false=""
     [ "$var" ] &amp;&amp; echo var is true
     [ -z "$var" ] &amp;&amp; echo var is false</pre>
<p>Test of variables containing ANY string  (see PROBLEM CASES below)</p>
<pre>
     option=-xyzzy
     [ "X$option" != X ] &amp;&amp; echo option is defined
     [ "X$a" = "X$b" ] &amp;&amp; echo "$a equals $b"</pre>
<p>Rules of thumb&#8230;<br />
* Always quote all variables being tested<br />
* Only use the boolean type test (above) when<br />
all possible values are defineately known.<br />
* Prepend X (or other alphanumberic) to unknown strings being compared<br />
* Don&#8217;t use ! if you can avoid it.</p>
<p><strong>PROBLEM CASES&#8230;</strong></p>
<p>These cases cause the &#8220;[...]&#8221; tests to fail badly!</p>
<pre>
  [ $var ]         but  var="a = b"
  [ "$var" ]       but  var=-t  (actually any option starting with '-')
  [ "$a" = "$b" ]  but  a='('  and   b=')'</pre>
<p>This is why you must use the string test above (with &#8216;X&#8217; prefixes).</p>
<p>NOTE   test ! &#8230;  differs from UNIX to UNIX<br />
Under bash it is the NOT of the next 3 arguments following<br />
Under solaris &#8220;sh&#8221; it seems to handled with precedence.</p>
<p>EG:   test &#8220;&#8221; -a ! &#8220;&#8221;    is false as you would expect<br />
BUT   test ! &#8220;&#8221; -a &#8220;&#8221;    is true for BASH   and   false for Solaris SH</p>
<p><strong>Argument Sorting By Shells</strong></p>
<p>All Shells normally sort the output of any commands with meta characters.<br />
Also &#8220;ls&#8221; will sort its arguments again internally, while &#8220;echo&#8221; will not.</p>
<p>EG compare the output of these commands<br />
ls -d b* a*<br />
echo  b* a*<br />
echo  [ba]*</p>
<p>The first sorts the output so a&#8217;s are before b&#8217;s, the second does not.<br />
However the shell sorts the arguments of the third so a&#8217;s are again first.</p>
<p>However the &#8220;{}&#8221; meta characters do NOT sort the results&#8230;<br />
echo {b,a}*<br />
will output b&#8217;s first then a&#8217;s.</p>
<p>This can be useful when the order of the arguments is important.</p>
<p>This has been tested and works as described in  csh, tcsh, bash, and zsh</p>
<p><strong>Argument handling&#8230;</strong></p>
<p>If you care for the possibility that there aren&#8217;t any arguments.<br />
&#8220;$@&#8221;         -&gt;    &#8220;&#8221;     (one empty argument)<br />
${1+&#8221;$@&#8221;}    -&gt; nothing at all<br />
This is not a problem with newer modern shells, only very old Bourne shells.</p>
<p>WARNING: Command line shell argument start at 0!</p>
<p>sh -c &#8216;echo $*&#8217; 1 2 3 4 5<br />
or  sh -c &#8216;echo $*&#8217; `seq 5`<br />
Will print<br />
2 3 4 5</p>
<p>Note that the first arguement is missing. That is because it was assigned to<br />
argument $0 and not $1 or the $@ and $* variables!</p>
<p>To use all the arguments on the shell command line, use either<br />
sh -c &#8216;echo $*&#8217; junk `seq 5`<br />
or<br />
sh -c &#8216;echo $0 $*&#8217; `seq 5`</p>
<p>the later is not recomended as if no arguments are provided $0 defaults<br />
to &#8220;sh&#8221; instead of the empty string!</p>
<p>This is a posix compliant feature, $0 being the program name when a shell<br />
script is called. the &#8220;-c&#8221; command line script just layers on top of this.<br />
this is the case with solaris bourne sh, bash, ksh, and zsh.  csh and tcsh<br />
shell does not have an equivelence.</p>
<p>See &#8220;find&#8221; and its &#8220;-exec&#8221; option, (see below), for a useful example of this.</p>
<p>I also use it in csh aliases to provide a default argument.<br />
EG:  alias xvd  &#8216;sh -c &#8221;&#8217;cd ${1:-.}; xv -vsmap &amp;&#8221;&#8217; junk !:* &amp;&#8217;</p>
<p><strong>Auto change shells on brain dead systems (Ultrix)</strong></p>
<pre>
  #!/bin/sh -
  #
  # Check the type of shell that is running (For Ultrix)
  [ "X$1" != 'X-sh5' -a -f /bin/sh5 ] &amp;&amp; exec /bin/sh5 -$- "$0" -sh5 "$@"
  [ "X$1" = 'X-sh5' ] &amp;&amp; shift
  #</pre>
<p><strong>Getting environment from csh</strong></p>
<pre>
   env - DISPLAY=$DISPLAY HOME=$HOME TERM=dumb
         csh -cf 'set prompt="&gt; ";
                  source .cshrc; source .login;
                  echo "#------ENVIRONMENT------"
                  env' |
       sed -n '/#------ENVIRONMENT------/,$p'</pre>
<p><strong>Inserting a AWK or PERL script inside a SHELL script&#8230;</strong></p>
<p>Example&#8230;</p>
<pre>
    nawk '# output to mailx commands!
      /^[^ ]/ { recipent=$0; }
      /^ /    { print $0 &gt; "|mailx -s \"This is the test\" " recipent; }
      /^$/    { close( "|mailx -s \"This is the test\" " recipent );
      ' list.txt</pre>
<p>Note the whole script is inside single quotes on the nawk command line!</p>
<p>ASIDE: old versions of awk must have something on the first line thus the<br />
addition of the # comment to keep it happy!  Perl needs no such comment but<br />
does require a -e option to execute a command line argument.</p>
<p>To insert a external shell variable into the script you need to close<br />
the single quotes, output variable and re-open the single quotes. Also<br />
the variable sould be in double quotes so as to prvent any insertion of<br />
space characters</p>
<p>Example inserting a $prefix shell variable into a awk string.</p>
<pre>
       ...
       {  print "'"$prefix"'" $0; }
       ...</pre>
<p>Also to insert a single quote into the script you have to also exit the<br />
wrapping single quotes and supply it outside those quotes</p>
<pre>
       ...
       {  print "I just can'''t do that!"; }
       ...</pre>
<p>CAUTION: Watch for single quotes inside any COMMENTS which is in the script!<br />
Comments are within the single quotes so are also scanned for thos quotes.</p>
<p>CSH SCRIPTS: If you must write a csh script you will need to escape the new<br />
line at the end of every line, even though single quotes are being used, which<br />
requires to backslashes..  Also watch out for history escapes `!&#8217; which work<br />
inside single quotes!</p>
<p><strong>Is COMMAND available</strong></p>
<p>There is two techniques available to test if a command is available.<br />
The first is to use the `status&#8217; return of the &#8220;type&#8221; or &#8220;which&#8221; command<br />
of the shell you are using. The Second is to examine the output of that<br />
command itself.</p>
<p>Using status return.<br />
This is a simple method of testing the existance of a command<br />
but DOES NOT WORK ON ALL SYSTEMS!  The problem is that old shells<br />
(For Example: SunOS bourne-sh) always returns a true status weather<br />
the command is present or not!</p>
<p>Bourne Shell</p>
<pre>
     if  type COMMAND 2&gt;&amp;1; then
        # COMMAND is available
     fi</pre>
<p>C-Shell</p>
<p>Warning: The &#8220;which&#8221; command in  C shell is not a builtin but a external<br />
script which sources your .cshrc (YUCK). As such the bourne shell alias<br />
is prefered which will only search your current command PATH.</p>
<pre>
    if ( ! $?tcsh ) then
     alias which 'sh -c "type !:1 2&gt;&amp;1"'
    endif

    if ( -x "`which COMMAND &gt;/dev/null`" ) then
      # COMMAND Available
    endif</pre>
<p>TC-Shell</p>
<p>Tcsh 6.06 also does not return the correct status in its which<br />
command. Use it like the csh which above.</p>
<p>WARNING: this method will also test positive for :-<br />
subroutines, bash aliases, and probably other non-command definitions.</p>
<p>Examine output<br />
The other am more reliable method is to examine the output of the<br />
&#8220;type&#8221; or &#8220;which&#8221; command to looks for the string &#8220;not found&#8221; (See<br />
below).  This is more complex than the above status check but should<br />
work on ALL unix machines regardless of age.</p>
<p>Bourne Shell</p>
<pre>
    cmd_found() {
      case "`type $1 2&gt;&amp;1`" in *'not found'*) return 1 ;; esac; return 0
    }
    ...
    if  cmd_found COMMAND; then
      # COMMAND is available
    fi</pre>
<p>C-Shell &amp; Tcsh   (See notes below)</p>
<pre>
    if ( ! $?tcsh ) then
      alias which 'sh -c "type !:1 2&gt;&amp;1"'
    endif
    ...
    if ( "`which less`" !~ *'not found'* ) then
      # COMMAND Available
    endif</pre>
<p>NOTES for &#8220;which/type&#8221; commands :-</p>
<p>The above methods look for the specific string  &#8220;not found&#8221;<br />
This is important as the sh  type command  and tcsh which command<br />
produce different output, and this may also vary from bourne shell<br />
to bourne shell or other shell types.</p>
<p>Csh  &#8212; &#8220;which&#8221; is an unreliable shell script!<br />
fudge it into a shell script &#8220;type&#8221; command.<br />
See the &#8220;Which Problem&#8221; below.</p>
<p>Tcsh<br />
&gt; which less<br />
/opt/bin/less<br />
&gt; which junk<br />
junk: Command not found.<br />
&gt; which which<br />
which: shell built-in command.<br />
&gt; alias a alias<br />
&gt; which a<br />
a:  aliased to alias</p>
<p>Solaris Bourne shell<br />
&gt; type less<br />
less is /opt/bin/less<br />
&gt; type junk<br />
junk not found<br />
&gt; type type<br />
type is a shell builtin<br />
&gt; func(){ echo ha; }<br />
&gt; type func<br />
func is a function<br />
func(){<br />
echo ha<br />
}</p>
<p>Solaris Ksh<br />
As per Sh, but the actual function definition is NOT listed</p>
<p>Bash<br />
&gt; type less<br />
less is /opt/bin/less<br />
&gt; type junk<br />
bash: type: junk: not found<br />
&gt; type type<br />
type is a shell builtin<br />
&gt; func(){ echo ha; }<br />
&gt; type func<br />
func is a function<br />
func ()<br />
{<br />
echo ha<br />
}<br />
NOTE: bash also has a type -t which responds with a single word &#8220;file&#8221;,<br />
&#8220;alias&#8221;, &#8220;function&#8221;, &#8220;builtin&#8221;, &#8220;keyword&#8221;, or nothing if command does not<br />
exist.  A -p will print the disk file name, or nothing. A -a prints all the<br />
places that have that name.</p>
<p>From the results above, only the appearence of  &#8220;not found&#8221; in the false<br />
statement is consistant.  But only when the result is not a bourne shell<br />
function, which presumably replaces the real-command of that name.</p>
<p>The Expanded Bourne shell form, without using the &#8220;cmd_found&#8221; function is as<br />
follows, But is is a low simpler and easier to read if you use the funtion.</p>
<p>If command present</p>
<p>if  expr match &#8220;`type COMMAND 2&gt;&amp;1`&#8221; &#8216;.*not found&#8217; == 0 &gt;/dev/null;  then<br />
# COMMAND is available<br />
fi</p>
<p>and its inverse (not present)</p>
<p>if  expr match &#8220;`type COMMAND 2&gt;&amp;1`&#8221; &#8216;.*not found&#8217; &gt;/dev/null;  then<br />
# Comand is NOT present<br />
fi</p>
<p>finally only using built-in commands&#8230;</p>
<p>case &#8220;`type COMMAND`&#8221; in<br />
*&#8217;not found&#8217;*) # Command not found ;;<br />
*)             # Command found ;;<br />
esac</p>
<p>Functional forms<br />
cmd_found() {<br />
expr match &#8220;`type $1 2&gt;&amp;1`&#8221; &#8216;.*not found&#8217; == 0 &gt;/dev/null<br />
}<br />
OR<br />
cmd_found() {<br />
case &#8220;`type $1 2&gt;&amp;1`&#8221; in *&#8217;not found&#8217;*) return 1 ;; esac; return 0<br />
}</p>
<p><strong>Which problem!</strong></p>
<p>The which command is a csh script that specifically reads the .cshrc<br />
file to find out about aliases. To avoid having .cshrc do lots of odd<br />
things to your script, use the following form.</p>
<p>set program = `/bin/env HOME= /usr/ucb/which $program`</p>
<p>This is NOT a problem in Tcsh, where &#8220;which&#8221; is a built-in.</p>
<p>The best solution it to replace &#8220;which&#8221; with the bourne shell &#8220;type&#8221; command<br />
in C shells but leave it alone for TC shells.</p>
<p>if ( ! $?tcsh ) then<br />
alias which &#8216;sh -c &#8220;type !:1 2&gt;&amp;1&#8243; | sed &#8220;s/.* is //&#8221;&#8216;<br />
endif</p>
<p>set program = `which $program`</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
<strong>builtin cat command</strong></p>
<p>This cat only uses the shell builtins! As such can be used on a machine<br />
which has no access to shared libraries and nothing but the statically<br />
linked bourne sh can run.</p>
<p>shcat() {<br />
while test $# -ge 1; do<br />
while read i; do<br />
echo &#8220;$i&#8221;<br />
done &lt; $1<br />
shift<br />
done<br />
}</p>
<p>Of course the real cat command is only as big as it is, to protect the<br />
user from himself and to provide a huge number of options.</p>
<p>PS:  If the   ls   command is also not available then you can use</p>
<p>echo *</p>
<p>to do a directory listing using only builtins. Though this will not tell<br />
you what files are executables or sub-directories.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Note `cmd` does save the newline characters within the output</p>
<p>::::&gt; m=`mount`;<br />
::::&gt; echo $m<br />
/ /usr /home<br />
::::&gt; echo &#8220;$m&#8221;<br />
/<br />
/usr<br />
/home</p>
<p>In other words outside quotes newlines in the input are treated purely<br />
as white space between arguments and thus ignored. Inside quotes<br />
newlines are retained as newlines.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
One line if-then-else shell command</p>
<p>cmd1 &amp;&amp; cmd2 || cmd3</p>
<p>This hoever will execute cmd3 if cmd2 fails!  If cmd2 never fails &#8212; fine</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
The useless use of &#8216;cat&#8217;!</p>
<p>You often see in shell scripts&#8230;</p>
<p>cat input_file | some_command</p>
<p>The cat is usless as it is exactly the same as</p>
<p>some_command &lt; input_file</p>
<p>without needing to fork the extra &#8220;cat&#8221; process or creating a pipeline.<br />
However it is sometimes usefull to do anyway to make the code more readable.<br />
Particularly in long pipelines.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Cat with here file and pipe to another command  (Shell Syntax Example)</p>
<p>cat &lt;<eof><br />
&#8230;..<br />
E0F<br />
while  read line;  do<br />
&#8230;<br />
done</eof></p>
<p>This is also a &#8220;Useless use of &#8216;cat&#8217;!&#8221;.  The equivelent without cat is&#8230;</p>
<p>while  read line;  do<br />
&#8230;<br />
done &lt;<eof><br />
&#8230;..<br />
EOF</eof></p>
<p>Of course the &#8220;cat&#8221; could be a &#8220;sed&#8221; &#8220;awk&#8221; or other filter of the here file<br />
data before you feed it into the while loop.</p>
<p>Also in the second method, the here file is then at the end, which can be<br />
confusing for later code readers as their is no indication at the start of the<br />
loop you are reading from a here file and not from the stdandard input of the<br />
script.</p>
<p>Because of this I usally prefer the cat, unless the while-loop is very very<br />
short.</p>
<p>WARNING: See the &#8220;non-posix shell bug&#8221; below</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Non-Posix shell bug</p>
<p>foo=bar<br />
while read line<br />
do<br />
foo=bletch<br />
done &lt; /etc/passwd<br />
echo &#8220;foo = $foo&#8221;</p>
<p>In some shells redirecting a file into a control structure will use a<br />
sub-shell for that structure.  In the above this will result in &#8220;foo =<br />
bar&#8221; instead of  &#8220;foo = bletch&#8221; assigned in the while loop.</p>
<p>The POSIX standard forbids this behaviour.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
echo without a return (bsd &amp; sysV)</p>
<p>For Bourne Shell</p>
<p># echo without a return (bsd &amp; sysV)<br />
if [ "X`echo -n`" = "X-n" ]; then<br />
echo_n() { echo ${1+&#8221;$@&#8221;}&#8221;c&#8221;; }<br />
else<br />
echo_n() { echo -n ${1+&#8221;$@&#8221;}; }<br />
fi</p>
<p>For Csh or Tcsh (which you shouldn&#8217;t use for scripts anyway)</p>
<p># echo without a return (bsd &amp; sysV)<br />
if ( &#8220;X`echo -n`&#8221; == &#8216;X-n&#8217; ) then<br />
alias echo_n &#8216;echo !:* &#8220;c&#8221;&#8216;<br />
else<br />
alias echo_n &#8216;echo -n !:* &#8216;<br />
endif</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Columizing data</p>
<p>pr<br />
To convert a file (or part of a file) to columns.<br />
Warning: this program will truncate data to fit into space available!</p>
<p>Example file:  numbers 1 &#8211; 10, one number per line<br />
It is recomended that the -# be the first option.</p>
<p>Down the columns (like ls)<br />
pr -3 -t -l3<br />
|  `&#8211; number of columns<br />
`&#8212;&#8211; lines per column (very important to give correctly)<br />
if output width is a problem add  -w80<br />
EG: seq -f %02g 10 | pr -3 -t -l3 -w30<br />
Outputs:  01       04       07<br />
02       05       08<br />
03       06       09<br />
10</p>
<p>Or on most linux machines..<br />
column -x -c30<br />
`&#8212; width of output line</p>
<p>Across<br />
paste &#8211; - -<br />
Number of &#8211; given determines number of columns<br />
EG: seq 10 | paste &#8211; - -<br />
Outputs:  01       02       03<br />
04       05       06<br />
07       08       09<br />
10<br />
OR (with posible data truncation to fit ouptput line width)<br />
pr -t -l1 -3</p>
<p>column<br />
On linux to just put the data into columns use &#8220;column&#8221;<br />
CAUTION: any meta-characters found will may column silently ABORT,<br />
truncating the file being processed!</p>
<p>Example:<br />
seq -f %03g 5 5 500 | column</p>
<p>This can also format text tables using &#8220;-t&#8221; function of column to preserve<br />
the line by line structure of the input file.</p>
<p>column -s: -t /etc/group</p>
<p>OR a more complex example&#8230;</p>
<p>( echo &#8220;PERM LINKS OWNER GROUP SIZE MONTH DAY HH:MM NAME&#8221;;<br />
ls -l | tail -n+2;<br />
) | column -t</p>
<p>Warnings:<br />
* It also does not work as well as should<br />
EG: compare the output of   &#8220;ls&#8221;  and &#8220;ls | column&#8221;<br />
* Tabs are used.  Use the &#8220;expand&#8221; filter to remove them before using<br />
the &#8220;column&#8221; filter.</p>
<p>You can also using a non-standard perl module (from CPAN)</p>
<p>seq -f %03g 100 |<br />
perl -MArray::PrintCols -e &#8216;@a=&lt;&gt;; chomp @a; print_cols @a&#8217;</p>
<p>Otherwise manually handle columns in perl</p>
<p>seq -f %03g 100 |<br />
perl -e &#8216;  @a=&lt;&gt;; chomp @a;<br />
my ( $c, $i ) = (10,10);<br />
foreach ( @a ) {<br />
print(&#8220;n&#8221;),$i=$c  unless $i;<br />
printf &#8221;  %4s&#8221;, $_;   $i&#8211;;<br />
} print &#8220;n&#8221;; &#8216;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Suppressing the shell background fork message (*csh)</p>
<p>The trick is to redirect the standard error output of the _shell_ itself</p>
<p>Korn (with loss of standard error)</p>
<p>( command &amp; ) 2&gt;/dev/null</p>
<p>csh/tcsh (this appears to work)</p>
<p>( command &amp; )</p>
<p>bourne shell does not give a message about background forks ever.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Auto Background a shell script<br />
#!/bin/csh -f<br />
if ( $1:q != &#8216;&#8230;&#8217; ) then<br />
( $0 &#8216;&#8230;&#8217; $*:q &amp; )<br />
exit 0<br />
endif<br />
shift<br />
&#8230;rest of script to run in background&#8230;</p>
<p>OR<br />
#!/bin/sh<br />
foreground stuff<br />
( background stuff<br />
) &amp;<br />
exit</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Sort a shell array</p>
<p>=======8&lt; &#8212;&#8212;&#8211;<br />
i=0<br />
for n ;<br />
do<br />
Â  a[$((i++))]=$n ;<br />
done</p>
<p># sort array</p>
<p>for (( i=0; $i&lt;(${#a[@]}-1); i++ )) ;<br />
do<br />
Â  for (( j=i+1; $j&lt;(${#a[@]}); j++ )) ;<br />
Â  do<br />
Â Â Â  if [[ ${a[$j]} &lt; ${a[$i]} ]] ;<br />
Â Â Â  then<br />
Â Â Â Â Â  t=${a[$j]};<br />
Â Â Â Â Â  a[$j]=${a[$i]};<br />
Â Â Â Â Â  a[$i]=$t;<br />
Â Â Â  fi<br />
Â  done<br />
done</p>
<p># launch xmms with sorted list<br />
xmms -e &#8220;${a[@]}&#8221;<br />
=======8&lt;&#8212;&#8212;&#8211;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Command timeout</p>
<p>Run a command but kill it if it runs for too long. This prevents scripts<br />
hanging on a command, especially network related commands, like nslookup.</p>
<p>Simple C solution&#8230;<br />
Look at ~/store/c/programs/timeout.c  which will timeout a command<br />
simply and easilly.  A lot better than the complex solutions below.</p>
<p>&#8212;- Attempt 1 &#8212;-<br />
Runs the command in the background and waits for it to<br />
complete. A sleep command is also run to provide a timeout.</p>
<p>Works but full timeout period is always waited before exiting</p>
<p>TIMEOUT=60  # timelimit for command<br />
( command_which_can_hang &amp;<br />
sleep $TIMEOUT; kill $! 2&gt;/dev/null<br />
)</p>
<p>This does not work. We will wait on the sleep for the full TIMEOUT period<br />
regardless of how fast the command completes.  If the command is known to<br />
never finish then the above will be fine!</p>
<p>&#8212;- Attempt 2 &#8212;&#8211;<br />
Works for modern day shells&#8230;</p>
<p>do_quota() {<br />
# lookup the users disk quota but with a timeout<br />
quota -v &#8220;$@&#8221; &amp;<br />
# now ensure that the above command does not run too long<br />
cmd_pid=$!<br />
( sleep $QUOTA_TIMEOUT<br />
echo &gt;&amp;2 &#8220;Quota Timeout&#8221;<br />
kill -9 $cmd_pid 2&gt;/dev/null<br />
) &amp;<br />
kill_pid=$!<br />
wait $cmd_pid<br />
kill $kill_pid 2&gt;/dev/null<br />
}</p>
<p>The problem here is that this works fine but the sleep will still continue<br />
for the full timeout period. Basically the parent has no simple way of<br />
determining the PID of the sleep, to abort it, if it was not needed.  This is<br />
not a problem if the sleep itself is not too long, so it doesn&#8217;t stick around<br />
for hour.</p>
<p>The sub-shell however is killed, so the kill command is not run if the command<br />
completes before the timeout</p>
<p>Unfortunatally BASH generates a &#8220;terminate&#8221; message on standard out when<br />
the command is killed due to timeout :-(</p>
<p>Full Example<br />
try with/without a timeout argument of 15&#8230;</p>
<p>=======8&lt; &#8212;&#8212;&#8211;<br />
#!/bin/sh<br />
#<br />
# Countdown [abort_after]<br />
#<br />
COUNTDOWN_FROM=10          # count down from this value<br />
COUNTDOWN_ABORT=${1:-4}    # abort countdown after this long</p>
<p>countdown() {<br />
i=$COUNTDOWN_FROM<br />
echo &#8220;Countdown continuing at T minus $i&#8221;<br />
while [ $i -gt 0 ]; do<br />
sleep 1<br />
i=`expr $i &#8211; 1`<br />
[ $i -eq 3 ] &amp;&amp; echo &#8220;Main engine start&#8221;<br />
|| echo &#8220;&#8211;&gt; $i&#8221;<br />
done<br />
echo &#8220;We have lift off!!!&#8221;<br />
exit 0;<br />
}</p>
<p>countdown &amp;   # the command that we wish to timeout<br />
cmd_pid=$!</p>
<p>( sleep $COUNTDOWN_ABORT;<br />
kill $cmd_pid<br />
echo &#8220;countdown aborted&#8221;;<br />
) &amp;<br />
kill_pid=$!</p>
<p>wait $cmd_pid<br />
echo &#8220;Launch status: $?&#8221;</p>
<p>kill $kill_pid 2&gt;/dev/null</p>
<p>#/bin/ps   # uncomment to show if sleep is still running</p>
<p>=======8&lt; &#8212;&#8212;&#8211;</p>
<p>&#8212;- Attempt 3 &#8212;-<br />
Reports a `Terminate&#8217; error to stdout if command timesout.</p>
<p>TIMEOUT=60  # timelimit for command<br />
command_which_can_hang &amp;<br />
cmd_pid=$!<br />
sleep $TIMEOUT | (<br />
read nothing  # wait on sleep to finish<br />
kill $cmd_pid 2&gt;/dev/null;            # otherwise abort the command!<br />
) &amp;<br />
sleep_pid=$!<br />
wait $cmd_pid<br />
kill -ALRM $sleep_pid 2&gt;/dev/null     # kill sleep if still running</p>
<p>The reason this works is that we are specifically killing the sleep (we hope).<br />
This is because $! returns the pid of the first command in a command pipeline,<br />
so we fake such a pipeline.</p>
<p>WARNING: Some shells may have $! set to the last command in pipeline!  which<br />
make this equivelent to &#8220;Attempt 2&#8243; though will also work as expected.</p>
<p>Using an ALRM signal to kill sleep is especially good as it means sleep exits<br />
normally and cleanly, stopping a shell like &#8220;bash&#8221; from producing &#8220;Terminated&#8221;<br />
messages all over the place.</p>
<p>In the &#8220;kill command&#8221; sub-shell, the &#8220;read&#8221; is needed to ensure it waits for<br />
non-existant output from the sleep command. It will automatically exit when<br />
the sleep exits without producing any output.</p>
<p>A &#8220;kill -0 $pid&#8221; could be used to check if the pid given is still running or<br />
not, and in a full working version is probably a good idea.</p>
<p>I suppose we could also backgound the sleep, and have a background kill<br />
process wait specifically on the background sleep process but this seems to<br />
complex to me&#8230;.  It also does NOT work as you wither have to put a a wait<br />
for the sleep the sub-shell (or a looped pid poll) which did NOT launch the<br />
sleep and thus does not know its pid, or the background sleep in the<br />
sub-shell, in which case the main script did not launch it so can&#8217;t abort it.<br />
Very difficult to sort that out.  Better to use a command pipeline.</p>
<p>I supose you could use a `SIGCHLD trap&#8217; but that is a completely different<br />
method.  If anyone have created such a trap in shell, please email me your<br />
code, so I can include it here (with your name of course).</p>
<p>Full example..</p>
<p>TIMEOUT=20    # Limit name server lookup to 20 seconds<br />
# &#8230;<br />
do_nslookup() {<br />
# Do a FAST nslookup &#8211; even if primary namserver is down<br />
# Background the required command &#8211; note the process id<br />
# any output to be printed to standard argument and calling function<br />
nslookup 2&gt;/dev/null &lt; &lt;-EOF | sed -n &#8216;/arpa/s/.*name = //p&#8217; &amp;<br />
set type=PTR<br />
$1<br />
EOF<br />
cmd_pid=$!<br />
#<br />
# Wait for it (sleep pipeline) &#8211; note sleep&#8217;s process id<br />
sleep $TIMEOUT | (<br />
read nothing  # wait on sleep to finish<br />
kill -0 $cmd_pid 2&gt;/dev/null || exit;  # cmd finished? &#8211; exit sub-shell<br />
kill $cmd_pid 2&gt;/dev/null;<br />
echo &gt;&amp;2 &#8220;WARNING: nslookup failed to return in $TIMEOUT seconds!&#8221;<br />
) &amp;<br />
sleep_pid=$!<br />
#<br />
# wait for nslookup to finish or be killed<br />
wait $cmd_pid<br />
kill -0 $sleep_pid 2&gt;/dev/null || return;  # sleep finished?<br />
kill $sleep_pid 2&gt;/dev/null<br />
}<br />
# &#8230;<br />
Reverse_IP_Arg=&#8221;4.3.2.1.in-addr.arpa&#8221;<br />
FQDN_hostname=`do_nslookup $Reverse_IP_Arg`</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Loop until parent process dies</p>
<p>Background tasks have an annoying habit of continuing to run AFTER you have<br />
logged out. This following example program looks up the launching parent<br />
process (typically your login shell) and only loops if the parent process is<br />
still alive.</p>
<p>WARNING: The PS command varies from UNIX system to UNIX system so you will<br />
have to tweek the arguments to the `ps&#8217; command to make this script work on<br />
your UNIX system</p>
<p>=======8&lt; &#8212;&#8212;&#8211;<br />
#!/bin/sh<br />
#<br />
# Loop until parent dies<br />
#<br />
sleep_time=300     # time between background checks</p>
<p># Pick the appropriate ps options for your UNIX system<br />
# Uncomment ONE of the following lines<br />
#job_opt=xj; sep=&#8221;";  ppid=1;   # SunOS<br />
job_opt=xl; sep=&#8221; &#8220;; ppid=4;   # Solaris<br />
#job_opt=xl; sep=&#8221; &#8220;; ppid=4;   # IBM UNIX (aix)<br />
#job_opt=xl; sep=&#8221; &#8220;; ppid=4;   # SGI UNIX (irix)</p>
<p># Discover the parents process ID<br />
set &#8211; `ps $job_opt$sep$$ | tail -n+2` &#8220;1&#8243;<br />
eval parent=$$ppid</p>
<p># While parent is still alive<br />
# The  kill command &#8220;-0&#8243; option checks to see if process is alive!<br />
# It does NOT actually kill the process (EG: test process)<br />
while  kill -0 $parent 2&gt;/dev/null; do<br />
# &#8230;<br />
# Do the background job here<br />
# &#8230;<br />
sleep $sleep_time<br />
done</p>
<p># Parent process has died so we also better die.<br />
exit 0<br />
=======8&lt; &#8212;&#8212;&#8211;</p>
<p>Also see the script   ~anthony/bin/scripts/hostspace<br />
as an example of a shell script for multiple hosts</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Convert ls permissions to octal format</p>
<p>&#8230; anyone? &#8230;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Time in Seconds, NOW!  (for later comparision)</p>
<p>EG: getting the number of seconds since epoch (midnight, 1/1/1970, GMT)</p>
<p>This is for the purposes of timing various command and comparing the start<br />
and end times.  The problem is as there is no standard way for geting the<br />
system clock under normal plain shell scripts.</p>
<p>Under linux (Gnu-date) you can<br />
date +%s</p>
<p>With perl you can<br />
perl -e &#8216;print time(), &#8220;n&#8221;&#8216;</p>
<p>This seems to work very well on all system I know of, and can be used for<br />
sequencing events. Do not rely on it for time deltas (how long) as it does not<br />
handle years (%j is day within the year)</p>
<p>date +&#8217;%j * 86400 + %H * 3600 + %M * 60 + %S&#8217; | bc</p>
<p>Convert Time since epoch to Date<br />
(for more see the perl/general.hints page)<br />
perl -e &#8216;require &#8220;ctime.pl&#8221;; print &amp;ctime(1000000000);</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Get the date of yesterday (without a lot of fuss)</p>
<p>Getting yesterdays day is usually best done in either C or perl.</p>
<p>#!/usr/bin/perl<br />
require &#8220;ctime.pl&#8221;;<br />
print &amp;ctime($^T &#8211; 60*60*24);</p>
<p>By changing your timezone you can fake the getting of yesterdays date,<br />
But ONLY if you live in Australia where it is already tomorrow!.<br />
It is not perfect (2 hours short but close enough in most cases)</p>
<p>env TZ=GMT-12 date</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Four Digit Year in shell (for logfiles)</p>
<p>For Newer UNIX Machines, IEEE date format</p>
<p>date=`date +&#8217;%Y-%m-%d %R:%S&#8217;`</p>
<p>For Older UNIX machines (SunOS)&#8230;<br />
While the newest UNIX&#8217;s allow a %Y for a four digit year older machines<br />
like SunOS does NOT. This means the year will need to be extracted<br />
from the date output (or auturnative format code).</p>
<p>year=`date | sed &#8216;s/.*([0-9][0-9][0-9][0-9]).*/1/&#8217;`<br />
date=`date $year-%m-%d %H:%M:%S&#8221;</p>
<p>If you have the MH mail system install you can convert the date to rfc822 date<br />
format, use the &#8220;dp&#8221; program. This has its own mh output format codes.</p>
<p>/usr/lib/mh/dp &#8220;`date`&#8221;<br />
or  /usr/lib/mh/dp -format &#8216;%(year{text})&#8217; &#8220;`date`&#8221;<br />
or  /usr/lib/mh/dp<br />
-format &#8216;%04(year{text})-%02(mon{text})-%02(mday{text})&#8217;<br />
&#8220;`date`&#8221;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Setting a timed alarm in shell<br />
This can be done (as a background task) exactly how is an another matter<br />
As an educated guess probably something like..</p>
<p># Trap the USR1 signal<br />
trap &#8220;do timeout commands&#8221; 16<br />
( sleep $timeout; kill -16 $$; ) &amp;</p>
<p>See also  &#8220;Command timeout&#8221; above which was a later addition to this file.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Am I a Non-Interactive Shell</p>
<p>bourne sh:<br />
if [ -z "$PS1" ]; then   # script/remote execution (non-interactive)<br />
csh:<br />
if ( ! $?prompt ) then   # script/remote execution (non-interactive)</p>
<p>In the bourne shell a better way is to test the shell options &#8220;$-&#8221;<br />
for the interactive flag directly.</p>
<p>case $- in<br />
*i*) ;;   # do things for interactive shell<br />
*)   ;;   # do things for non-interactive shell<br />
esac</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Merge multiple blank lines into one line.</p>
<p>This is not easy, as we want to preserve a blank line, removing extras.<br />
Two methods,  print paragraphs, or delete extra blanks.</p>
<p>awk &#8216;{ printf &#8220;%s &#8220;, $0 } NF == 0 { print &#8220;n&#8221; }&#8217; filename</p>
<p>cat -s    # will do this (if available)</p>
<p>perl -ne &#8216;if (/S/) { print; $i=0 } else {print unless $i; $i=1; }&#8217;</p>
<p>perl -ne &#8216;print if /S/../^s*$/&#8217;</p>
<p>sed &#8216;/./,/^$/!d&#8217;               # NOTE: (t)csh users must backslash the !<br />
sed &#8216;/[^      ]/,/^[  ]*$/!d&#8217;  # For blank lines with spaces and tabs</p>
<p># Line joining in the vim editor!  as a macro<br />
:map QE  :$s/$/rZ/<cr>:g/^[ <tab>]*$/,/[^ </tab><tab>]/-j<cr>Gdd<br />
or       :%s/ns*n(s*n)*/rr/</cr></tab></cr></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
LIST functions<br />
(Also usable for PATH-like environment variables)</p>
<p>list=&#8221;list_variable&#8221;              # a:b:c:d<br />
element=&#8221;element_of_list&#8221;         # e<br />
sep=&#8221;list_seperator&#8221;              # :</p>
<p>Append to list (even if empty!)<br />
list=&#8221;${list:+$list$sep}$element&#8221;</p>
<p>Split up list<br />
function split_path () {<br />
( IFS=&#8221;$sep&#8221;<br />
set &#8212; $list<br />
for f in &#8220;$@&#8221;; do<br />
echo -n &#8220;${f:-.} &#8221;<br />
done; echo<br />
)<br />
}</p>
<p>Count of elements<br />
count=`IFS=&#8221;$sep&#8221;; set &#8211; $list; echo $#`</p>
<p>get I&#8217;th element (shell must understand shift argument)<br />
element=`IFS=&#8221;$sep&#8221;; set &#8211; $list; shift $I; echo $1`</p>
<p>get first element<br />
element=`IFS=&#8221;$sep&#8221;; set &#8211; $list; echo $1`</p>
<p>delete first element<br />
list=`echo &#8220;$list&#8221; | sed &#8220;/$sep/!d; /:/s/^[^$sep]*$sep//;&#8221;`</p>
<p>delete specific element over the whole list<br />
list=`echo &#8220;$list&#8221; | sed &#8220;s|${element}${sep}||g; s|${sep}${element}$||;&#8221;`</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Checking for a numerical value<br />
case &#8220;$var&#8221; in<br />
&#8221; | *[!0-9]*)  echo &#8220;non-numeric&#8221; ;;<br />
*)              echo &#8220;numeric&#8221; ;;<br />
esac                     # &#8212; Nick Holloway  (alfie@dcs.warwick.ac.uk)<br />
OR<br />
echo &#8220;$arg&#8221; | egrep &#8216;^[0-9]+$&#8217; &gt;/dev/null || echo &#8220;not-numeric&#8221;</p>
<p>Get value from option  (NOT zero)<br />
expr &#8220;$var&#8221; : &#8216;([0-9]*)$&#8217; || echo &#8220;not a non-zero-numeric value&#8221;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
random number generation in a shell<br />
nawk:<br />
set range  = ????<br />
set random = `nawk &#8216;BEGIN { srand();<br />
printf &#8220;%d&#8221;,  rand()*&#8217;$range&#8217;<br />
}&#8217; /dev/null`</p>
<p>date:<br />
set range  = ????     # file length &#8212; `wc -l &lt; $file`<br />
set date   = `date +%j%H%M%S`<br />
set random = `expr $date % $range`</p>
<p>(k/z/ba)sh<br />
$RANDOM<br />
Posible improvment&#8230;<br />
!/bin/bash<br />
MX=&#8221;0123456789&#8243;<br />
NL=&#8221;5&#8243;   # size of the random number wanted<br />
while [ ${n:=1} -le $NL ]<br />
do<br />
NUM=&#8221;$NUM${MX:$(($RANDOM%${#MX})):1}&#8221;<br />
let n+=1<br />
done<br />
echo &#8220;$NUM&#8221;</p>
<p>Programed (csh) (could be via expr too)<br />
set multiplier = 25173<br />
set modulus =    65536<br />
set increment =  13849<br />
set seedfile =   $HOME/.rnd  # seed file to use</p>
<p>if ( ! -f $seedfile ) then<br />
echo &#8217;17&#8242; &gt; $seedfile<br />
endif</p>
<p>@ number = ( `cat $seedfile` * $multiplier + $increment ) % $modulus<br />
echo $number &gt; $seedfile</p>
<p>@ number = $number % $range<br />
echo $number</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
increment a character in shell</p>
<p>char=`echo $char | tr &#8216; -~&#8217; &#8216;!-~&#8217;</p>
<p>or (sutable for hex chars)</p>
<p>str1=&#8221;ABCDEFGHIJKLMNOPQRSTUVWXYZ&#8221;<br />
str2=&#8221;BCDEFGHIJKLMNOPQRSTUVWXYZA&#8221;<br />
pos=`expr index $str1 $char`<br />
char=`expr substr $str2 $pos 1`<br />
echo $char</p>
<p>In perl the &#8220;increment alpha string&#8221; makes this easy</p>
<p>perl -e &#8216;$n=&#8221;&#8216;&#8221;$char&#8221;&#8216;&#8221;; print substr( ++$n, -1), &#8220;n&#8221;;&#8217;</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Protecting shell scripts from ^Z</p>
<p>This signal can&#8217;t normally be stoped in a shell, the trick is to change<br />
key generating the signal (Don&#8217;t forget to return it to normal).</p>
<p>stty susp undef      &#8212; if available<br />
stty susp &#8216;^-&#8217;       &#8212; maybe    system dependant</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Curses in shell script<br />
To use termcap entries in a shell script use the `tput&#8217; command<br />
EXAMPLES<br />
/usr/5bin/tput bold            # bold (extra half brigtht mode)<br />
/usr/5bin/tput bink            # bink mode (if available)<br />
/usr/5bin/tput rev             # reverse video<br />
/usr/5bin/tput smul            # underline mode<br />
/usr/5bin/tput smso            # standout (usually reverse)<br />
/usr/5bin/tput rmso            # end standout  (return to normal)<br />
/usr/5bin/tput clear           # clear screen<br />
/usr/5bin/tput cup 5 23        # cursor to move to row 5 column 23<br />
See terminfo(5) for more info.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
<strong>Split pipe into two separate commands (executable tee)</strong></p>
<p>awk &#8216;{ print | &#8220;&#8216;cmd1&#8242;&#8221; ; print }&#8217; | cmd 2</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Capitalize the first word.</p>
<p>The initial solutions in the news group cam out to more than 10 lines of code!</p>
<p># Ken Manheimer   (expr-tr-expr)  NOTE: fails if   word=&#8221;match&#8221;<br />
Word=`expr &#8220;$word&#8221; : &#8220;(.).*&#8221; | tr a-z A-Z&#8220;expr &#8220;$word&#8221; : &#8220;.(.*)&#8221;`</p>
<p># Paul Falstad    (cut-tr-sed)<br />
Word=`echo $word|tr a-z A-Z|cut -c1&#8220;echo $word|sed s/.//`</p>
<p>==&gt; # Logan Shaw     (cut-tr-cut)<br />
Word=`echo &#8220;$word&#8221; | cut -c1 | tr [a-z] [A-Z]&#8220;echo &#8220;$word&#8221; | cut -c2-`</p>
<p># Harald Eikrem (sed only)<br />
Word=`echo $word | sed  -e &#8216;<br />
h; &#8216;y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/;<br />
G; &#8216;s/(.).*n./1/; &#8216; `</p>
<p># Tom Christiansen  (perl)<br />
Word=`echo $word | perl -pe &#8216;s/.*/u$&amp;/&#8217;`</p>
<p># Jean-Michel Chenais <jean><br />
# (korn shell built-ins only)<br />
typeset -u W;typeset -l w;W=${word%${word#?}};w=$W;Word=$W${word#${w}}</jean></p>
<p># perl of course makes this easy<br />
perl -e &#8216;print &#8220;u&#8217;&#8221;$word&#8221;&#8216;&#8221;&#8216;</p>
<p><strong>Multi-line Paragraph handline</strong></p>
<p>Most text files including this one consists of paragraphs of multiple lines<br />
seperated by a blank line.</p>
<p>Convert all paragraphs into a single line (blank line seperated)</p>
<p>sed &#8216;/^$/d; :loop y/n/ /; N; /n$/! b loop;  s/   */ /g; s/^ //; s/ $//&#8217;</p>
<p>Also remove blank lines between paragraph lines</p>
<p>sed &#8216;/^$/d; :loop N; s/n$//; T loop; y/n/ /; s/   */ /g; s/^ //; s/ $//&#8217;</p>
<p>WARNING: better space handling is probably needed, especially for a last<br />
paragraph that has no final blank line after it.</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br />
Find a Process of a particular name                        &#8212; see csh alias pf</p>
<p>Usign grep</p>
<p>ps auxgww | grep &#8220;$NAME&#8221; | grep -v grep | cut -c1-15,36-99</p>
<p>Merging the two greps..</p>
<p>ps uxw | grep &#8220;[s]sh-agent&#8221; | awk &#8216;{print $2}&#8217;</p>
<p>The &#8220;[s]sh-agent&#8221;   will not match the grep process itself!<br />
EG: it will not match the &#8220;[s]sh-agent&#8221; string in the grep process</p>
<p>Using awk&#8230;</p>
<p>ps auxgww | awk &#8220;/$NAME/ &amp;&amp; ! /(awk)/&#8221; | cut -c1-15,36-99</p>
<p>or for a exact process name</p>
<p>ps auxgww | awk &#8216;/(^| |(|/)$NAME( |)|$)/&#8217; | cut -c1-15,36-99</p>
<p>or alturnativeally which matches under a lot of conditions&#8230;<br />
EG: matches    :01 NAME arg<br />
:01 some/path/NAME<br />
:01 NAME:</p>
<p>ps auxgww |<br />
awk &#8216;/:[0-9][0-9] (|[^ ]*/)$NAME($| |:)/&#8217; | cut -c1-15,36-99</p>
<p>Perl version (also matches on username)</p>
<p>ps auxgww |<br />
perl -nle &#8216;print if $. == 1<br />
|| /^s*!:1s/o<br />
|| /:dd (|[ *|[^ ]*/)!:1($|[]: ])/o; &#8216;</p>
<p>As you can see things can get complex very quickly</p>
<p><strong>Context Grep</strong><br />
Or how to display lines before/after search pattern.</p>
<p>GNU grep, has context built in to it, check out the -A, -B, and -C options.<br />
otherwise<br />
grep -v pattern file | diff -c3 &#8211; file | grep &#8216;^. &#8216; | colrm 1 2<br />
or<br />
grep -n $1 $2 | awk -F: &#8216;{ print $1 }&#8217; | while read linenum<br />
do<br />
awk &#8216;NR&gt;target-5 &amp;&amp; NR<target target="$linenum"><br />
echo &#8220;&#8212;&#8212;-next match&#8212;&#8212;&#8212;&#8221;<br />
done<br />
</target></p>
<p>Source: <a href="http://www.cit.gu.edu.au/~anthony/info/shell/script.hints">http://www.cit.gu.edu.au</a></p>
<script type="text/javascript">var wordpress_toolbar_urls = ["http:\/\/www.cit.gu.edu.au\/~anthony\/info\/shell\/script.hints"];var wordpress_toolbar_url = "http://pario.no/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "n";var wordpress_toolbar_hash = "aHR0cDovL3BhcmlvLm5vLzIwMDcvMDgvMzEvaGludHMtYW5kLXRpcHMtZm9yLWdlbmVyYWwtc2hlbGwtc2NyaXB0LXByb2dyYW1pbmcvPHdwdGI%2BSGludHMgYW5kIFRpcHMgZm9yIGdlbmVyYWwgc2hlbGwgc2NyaXB0IHByb2dyYW1taW5nPHdwdGI%2BaHR0cDovL3BhcmlvLm5vPHdwdGI%2BUGFyaW8gVGVjaG5vQmxvYg%3D%3D";</script>]]></content:encoded>
			<wfw:commentRss>http://pario.no/2007/08/31/hints-and-tips-for-general-shell-script-programing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shell script for search for no password entries and lock all accounts</title>
		<link>http://pario.no/2007/06/04/shell-script-for-search-for-no-password-entries-and-lock-all-accounts/</link>
		<comments>http://pario.no/2007/06/04/shell-script-for-search-for-no-password-entries-and-lock-all-accounts/#comments</comments>
		<pubDate>Mon, 04 Jun 2007 22:36:39 +0000</pubDate>
		<dc:creator>Hans-Henry Jakobsen</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[basename]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[grep]]></category>

		<guid isPermaLink="false">http://hhj.no/wordpress/2007/06/04/shell-script-for-search-for-no-password-entries-and-lock-all-accounts/</guid>
		<description><![CDATA[Shell script for search for no password entries and lock all accounts find-account-no-password.sh #!/bin/bash # Shell script for search for no password entries and lock all accounts # ------------------------------------------------------------------------- # Copyright (c) 2005 nixCraft project # This script is licensed under GNU GPL version 2.0 or above # ------------------------------------------------------------------------- # This script is part of [...]]]></description>
			<content:encoded><![CDATA[<p>Shell script for search for no password entries and lock all accounts</p>
<p><strong>find-account-no-password.sh </strong></p>
<pre>
#!/bin/bash
# Shell script for search for no password entries and lock all accounts
# -------------------------------------------------------------------------
# Copyright (c) 2005 nixCraft project <http>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
# Set your email
ADMINEMAIL="admin@somewhere.com"

### Do not change anything below ###
#LOG File
LOG="/root/nopassword.lock.log"
STATUS=0
TMPFILE="/tmp/null.mail.$$"

echo "-------------------------------------------------------" &gt;&gt;$LOG
echo "Host: $(hostname),  Run date: $(date)" &gt;&gt; $LOG
echo "-------------------------------------------------------" &gt;&gt;$LOG

# get all user names
USERS="$(cut -d: -f 1 /etc/passwd)"

# display message
echo "Searching for null password..."
for u in $USERS
do
  # find out if password is set or not (null password)
   passwd -S $u | grep -Ew "NP" &gt;/dev/null
   if [ $? -eq 0 ]; then # if so
     echo "$u" &gt;&gt; $LOG
     passwd -l $u #lock account
     STATUS=1  #update status so that we can send an email
   fi
done
echo "========================================================" &gt;&gt;$LOG
if [ $STATUS -eq 1 ]; then
   echo "Please see $LOG file and all account with no password are locked!" &gt;$TMPFILE
   echo "-- $(basename $0) script" &gt;&gt;$TMPFILE
   mail -s "Account with no password found and locked" "$ADMINEMAIL" &lt; $TMPFILE
#   rm -f $TMPFILE
fi
</http></pre>
<script type="text/javascript">var wordpress_toolbar_urls = [];var wordpress_toolbar_url = "http://pario.no/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "n";var wordpress_toolbar_hash = "aHR0cDovL3BhcmlvLm5vLzIwMDcvMDYvMDQvc2hlbGwtc2NyaXB0LWZvci1zZWFyY2gtZm9yLW5vLXBhc3N3b3JkLWVudHJpZXMtYW5kLWxvY2stYWxsLWFjY291bnRzLzx3cHRiPlNoZWxsIHNjcmlwdCBmb3Igc2VhcmNoIGZvciBubyBwYXNzd29yZCBlbnRyaWVzIGFuZCBsb2NrIGFsbCBhY2NvdW50czx3cHRiPmh0dHA6Ly9wYXJpby5ubzx3cHRiPlBhcmlvIFRlY2hub0Jsb2I%3D";</script>]]></content:encoded>
			<wfw:commentRss>http://pario.no/2007/06/04/shell-script-for-search-for-no-password-entries-and-lock-all-accounts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Bash shell script to reverse text file content</title>
		<link>http://pario.no/2007/06/04/bash-shell-script-to-reverse-text-file-content/</link>
		<comments>http://pario.no/2007/06/04/bash-shell-script-to-reverse-text-file-content/#comments</comments>
		<pubDate>Mon, 04 Jun 2007 22:34:44 +0000</pubDate>
		<dc:creator>Hans-Henry Jakobsen</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[basename]]></category>
		<category><![CDATA[bash]]></category>

		<guid isPermaLink="false">http://hhj.no/wordpress/2007/06/04/bash-shell-script-to-reverse-text-file-contain/</guid>
		<description><![CDATA[Shell script to reverse text file contain i.e. concatenate files and print on the standard output in reverse. This script also demonstrate how to use arrays under bash shell script. reverse-text-file.bash #!/bin/bash # Bash shell script to reverse text file contain i.e. concatenate files and # print on the standard output in reverse. This script [...]]]></description>
			<content:encoded><![CDATA[<p>Shell script to reverse text file contain i.e. concatenate files and print on the standard output in reverse. This script also demonstrate how to use arrays under bash shell script.</p>
<p><strong>reverse-text-file.bash </strong></p>
<pre>
#!/bin/bash
# Bash shell script to reverse text file contain i.e. concatenate files and
# print on the standard output in reverse. This script also demonstrate how
# to use arrays under bash shell script.
# -------------------------------------------------------------------------
# Copyright (c) 2005 nixCraft project <http>
# This script is licensed under GNU GPL version 2.0 or above
# -------------------------------------------------------------------------
# This script is part of nixCraft shell script collection (NSSC)
# Visit http://bash.cyberciti.biz/ for more information.
# -------------------------------------------------------------------------
FILE="$1"
if [ $# -eq 0 ]; then
  echo "$(basename $0) - file-name"
  exit 1
fi

textArray[0]="" # hold text
c=0 # counter
# read whole file in loop
while read line
do
  textArray[c]=$line # store line
  c=$(expr $c + 1) # increase counter by 1
done &lt; $FILE
# get length of array
len=$(expr $c - 1 )

# use for loop to reverse the array
for (( i=$len; i&gt;=0; i-- ));
do
  echo ${textArray[$i]}
done
</http></pre>
<script type="text/javascript">var wordpress_toolbar_urls = [];var wordpress_toolbar_url = "http://pario.no/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "n";var wordpress_toolbar_hash = "aHR0cDovL3BhcmlvLm5vLzIwMDcvMDYvMDQvYmFzaC1zaGVsbC1zY3JpcHQtdG8tcmV2ZXJzZS10ZXh0LWZpbGUtY29udGVudC88d3B0Yj5CYXNoIHNoZWxsIHNjcmlwdCB0byByZXZlcnNlIHRleHQgZmlsZSBjb250ZW50PHdwdGI%2BaHR0cDovL3BhcmlvLm5vPHdwdGI%2BUGFyaW8gVGVjaG5vQmxvYg%3D%3D";</script>]]></content:encoded>
			<wfw:commentRss>http://pario.no/2007/06/04/bash-shell-script-to-reverse-text-file-content/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Detecting changes to your network services/damons</title>
		<link>http://pario.no/2007/04/30/detecting-changes-to-your-network-servicesdamons/</link>
		<comments>http://pario.no/2007/04/30/detecting-changes-to-your-network-servicesdamons/#comments</comments>
		<pubDate>Mon, 30 Apr 2007 10:30:23 +0000</pubDate>
		<dc:creator>Hans-Henry Jakobsen</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[basename]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[diff]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[nmap]]></category>
		<category><![CDATA[perl]]></category>
		<category><![CDATA[ping]]></category>

		<guid isPermaLink="false">http://hhj.no/wordpress/2007/04/30/detecting-changes-to-your-network-servicesdamons/</guid>
		<description><![CDATA[This is a tutorial to detect changes in port from hosts on your network. The basic approach is to ping every available address upon your subnet and see which ones are up by detecting replies. If you install the package libperl-net-ping you can use the following script to see which hosts upon your LAN are [...]]]></description>
			<content:encoded><![CDATA[<p>This is a tutorial to detect changes in port from hosts on your network.<br />
The basic approach is to ping every available address upon your subnet and see which ones are up by detecting replies.</p>
<p>If you install the package libperl-net-ping you can use the following script to see which hosts upon your LAN are alive:</p>
<pre>
#!/usr/bin/perl -w

use strict;
use Net::Ping;

my $LAN = "192.168.1.";

foreach my $octet (1 .. 255)
{
	my $pinger = Net::Ping-&gt;new();
	if ( $pinger-&gt;ping( $LAN . $octet ) )
	{
		print  $LAN . $octet . "\n";
	}
	$pinger-&gt;close();
}</pre>
<p>Save the script as /usr/local/bin/scan-lan and make sure it&#8217;s executable by running chmod 755 /usr/local/bin/scan-lan.</p>
<p>This would give you a list of IP addresses which might look like the following:</p>
<pre>
192.168.1.1
192.168.1.2
192.168.1.10
192.168.1.50
192.168.1.90</pre>
<p>With a list like that saved to text file you can now start scanning your network for services.</p>
<p>In order to detect changes to our network we wish to record all the services on the machines in our LAN then later rescan to detect anything different.</p>
<p>Using the scan-lan and nmap we can create a file for each machine that&#8217;s up containing its services.</p>
<p>Save this script as /usr/local/bin/make-baseline, and make it executable with &#8220;chmod 755 /usr/local/bin/make-baseline&#8221;:</p>
<pre>
#!/bin/sh

mkdir -p /var/log/scans

for i in `/usr/local/bin/scan-lan` ; do
    nmap -sV $i | grep ' open ' &gt; /var/log/scans/$i.base
done</pre>
<p>This is our baseline scan. With this in hand we have a list of all the hosts upon a lan which are currently up, and the services they are running.</p>
<p>Now we just to write another script to compare the current state to that we recorded in our baseline, this will notify us of changes.</p>
<p>The following script can do that job for us, save it as /usr/local/bin/scan-services:</p>
<pre>
#!/bin/sh

if [ ! -d /var/log/scans ]; then
   echo "Baseline directory isn't present"
   exit
fi

#
#  Scan all the machines
#
for i in `/usr/local/bin/scan-lan` ; do
    nmap -sV $i | grep ' open ' &gt; /var/log/scans/$i.log
done

#
# Cleanup
#
rm /var/log/scans/*-added.txt
rm /var/log/scans/*-removed.txt
cd /var/log/scans/

#
# Find new and removed
#
for i in /var/log/scans/*.log; do
  diff --context $i ${i/.log/}.base | grep '^+ ' &gt; `basename $i .log`-added.txt
  diff --context $i ${i/.log/}.base | grep '^- ' &gt; `basename $i .log`-removed.txt
done

#
#  Now show the results
#
for i in /var/log/scans/*-added.txt; do
    if [ -s $i ]; then
      echo " "
      echo "The machine `basename $i -added.txt` has had the following services added:"
      cat $i
      echo " "
    fi
done

for i in /var/log/scans/*-removed.txt; do
    if [ -s $i ]; then
      echo " "
      echo "The machine `basename $i -removed.txt` has had the following services removed:"
      cat $i
      echo " "
    fi
done</pre>
<p>If you make this executable and run it you should see no output, as your current network hasn&#8217;t changed in the past few minutes.</p>
<p>Delete a line or two from one or more of the .base files in the /var/log/scans directory and run it again.</p>
<p>This time you should see output like this:</p>
<pre>
The machine 192.168.1.1 has had the following services added:
+ 8889/tcp open  http        GNUMP3d streaming server 2.9

The machine 127.0.0.1 has had the following services removed:
- 19/tcp   open  discard?</pre>
<script type="text/javascript">var wordpress_toolbar_urls = [];var wordpress_toolbar_url = "http://pario.no/wp-content/plugins/wordpress-toolbar/toolbar.php";var wordpress_toolbar_oinw = "n";var wordpress_toolbar_hash = "aHR0cDovL3BhcmlvLm5vLzIwMDcvMDQvMzAvZGV0ZWN0aW5nLWNoYW5nZXMtdG8teW91ci1uZXR3b3JrLXNlcnZpY2VzZGFtb25zLzx3cHRiPkRldGVjdGluZyBjaGFuZ2VzIHRvIHlvdXIgbmV0d29yayBzZXJ2aWNlcy9kYW1vbnM8d3B0Yj5odHRwOi8vcGFyaW8ubm88d3B0Yj5QYXJpbyBUZWNobm9CbG9i";</script>]]></content:encoded>
			<wfw:commentRss>http://pario.no/2007/04/30/detecting-changes-to-your-network-servicesdamons/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

