Hello there,

 : I'm writing a script to pull some stuff out of /var/log/messages 
 : by date.  I am having problems finding any entries with a single 
 : digit date because the messages file dates look like this: 
 : Mmm<space><space>d for single digit dates.  The output of

Some shell you are trying to run:

 : YESTERDAY=`date --date='yesterday'|cut -c 5-10`; echo $YESTERDAY

OK, so shell is absolutely wonderful.  I love it.

But, it can also cause you an unending headache with its rules for 
quoting and tokenizing.  It's smart to stuff the output into a 
variable.  But, then you throw a bit of 'echo' into your shell 
tokenization soup and you think that grep is eating your spaces!

So, let's back up a bit and look at this date space grep soup and 
see whether we can get you on the right track.  Here are some 
problems (or suboptimalities).
  
  1. Problem:  You are not quoting $YESTERDAY and the shell
     is eating your space (before echo gets it)

  2. Suboptimality: You could tell date to give you the string in 
     exactly the format you want.  (Avoid the unnecessary pipe.)

  3. Minor suboptimality:  You used a semicolon rather than an &&.

Here's what I would do:

  fgrep "$( date '+%b %e' --date 'yesterday' )" -- /var/log/messages


How did I get there?

  $ date '+%b %e' --date 'yesterday'
  Nov  3

OK, that looks like the string that I want to dig out of my log 
files.  Let's put that into a variable (the dollar parenthesis 
syntax is a nestable alternative to backticks for creating a 
parameter substitution subshell):

  YESTERDAY=$( date '+%b %e' --date 'yesterday' )

OK, so now, I just want to make sure that I have the right stuff in 
the variable.

  $ echo $YESTERDAY 
  Nov 3

Egads!  Somebody at my space!  (Ate MySpace? I guess it must have 
been FaceBottom.)  What could be happening here?  Well, I have heard 
that shell is picky about quoting, so perhaps I should quote this:

  $ echo "$YESTERDAY"
  Nov  3

Ah-ha!  So, the shell is eating my spaces.  So, what the heck is 
going on here?  This is called word-splitting.

The following is illustrative of what's going as the shell is 
processing your command [0].  Let's assume this:

  $ YESTERDAY=$( date '+%b %e' --date 'yesterday' )

  $ echo $YESTERDAY        # -- you typed this
    echo Nov  3            # -- expands the variable; note the space!
    echo Nov 3             # -- tokenizes, word-splitting here

    The tokenizing is done using IFS.  I don't suggest messing with 
    IFS, although some shell monsters do this.

    Now that the word-splitting is complete, bash calls the shell 
    builtin 'echo' and passes it two parameters.  The first 
    parameter is the word 'Nov' and the second parameter is the 
    word '3'.

    You now see on your screen something that looks like this:

  $ echo $YESTERDAY 
  Nov 3

So, what's different about the double quotes?  They tell bash to 
treat everything inside the quotes as a single shell word.  That's 
all they do.  Nothing more magical than that.

This is an excellent example and argument for getting into the 
general habit of quoting any shell variables.  You never know when 
you might end up with spaces in your shell variables, and this sort 
of problem (and many other, rather more dangerous problems) can 
result from bad shell quoting.

 : gives me Mmm<space>d for single digit dates.  Therein lies the 
 : problem - grep is looking for Nov 3 with one leading space while 
 : the messages file has Nov 3 with two leading spaces.  Gotta be a 
 : way to do this, I'm just not smart enough to figure it out.  
 : Pretty sure most of you guys are . . .

OK, so now, as you can probably see above, the date command takes a 
wide variety of options to control the format of its output.  By 
specifying the format of output you desire, you can dispense with 
the extraneous pipe to the 'cut' command.  This is a small win, but 
in a complex script it can make for an easier script to read and an 
easier script to debug later.

Naturally, being a creature familiar with Unix and comforted by its 
warm embrace, my favorite is:

   date +%s

I notice you are familiar with the --date option, as well.  This is 
wonderfully powerful!  If you have a recent GNU date, then you can 
even see one of my favorite Unix timestamps of all time:

  date +%F-%T --date '@1000000000'

Do you need the single quotes?  Nope.  It's just an old quoting 
habit on my part.

Finally, on another trivial little issue.  You used the semicolon to 
join together a few commands.  There's nothing terribly wrong with 
this, but if the commands are implicitly serial and you do not wish 
to execute the second command unless the first one succeeds, 
consider getting in the following habit:

 YESTERDAY=$( date '+%b %e' --date yesterday ) && echo "$YESTERDAY"

The 'echo "$YESTERDAY"' command will not be run unless the 
'YESTERDAY=$( date '+%b %e' --date yesterday )' command completes 
successfully.  This is a trivial matter for your script, but 
consider the following sort of archival situation:

  MYDIRECTORY=$( get_some_directory_name )
  run_huge_backup_job "$MYDIRECTORY"; rm -rf  "$MYDIRECTORY"

What do you suppose happens if run_huge_backup_job fails?

Oh, and yes, fgrep is just a another variant of grep for handling 
fixed strings.  This can be noticeably faster on large samples of 
input.

Have a great Friday and good luck!

-Martin

 [0] If you want more, go read the section on Expansion, 
     specifically word-splitting in the bash manpage, 'man 1 bash'.

P.S. If you are an advanced shell monster, consider using 'set -e' 
     and 'set -o pipefail' in your bash scripts.

-- 
Martin A. Brown
http://linux-ip.net/
_______________________________________________
PLUG mailing list
[email protected]
http://lists.pdxlinux.org/mailman/listinfo/plug

Reply via email to