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