LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   awk and shell expansion (https://www.linuxquestions.org/questions/linux-general-1/awk-and-shell-expansion-894391/)

Lagos 07-28-2011 09:28 PM

awk and shell expansion
 
hello:

I have a problem that I've solved but I'd like to better understand why it worked.

The particulars are as follows:

I have a log_file of the following form:

++++++++++
data
data
data
data
2011-07-27
data
data
++++++++++
data
data
2011-07-28
data
++++++++++

"++++++++++" ---> is my record separator

Objective: mail the record for a specific date.

Approach:

#!/bin/bash
i=`date +%F`
awk 'BEGIN{FS="\n"; RS="++++++++++"} /'$i'/ {print $0}' log_file >/tmp/alert
mail -s "mydata" root@localhost < /tmp/alert


In my inbox I find

data
data
2011-07-28
data


Excellent.

Now, trying to do things in one fell swoop why wouldn't the following work?

awk 'BEGIN{FS="\n"; RS="++++++++++"; "date +F%"|getline dateVal} /dateVal/ {print $0}' log_file >/tmp/alert

Can someone help me understand:

1. Why this second option does not work?

2. How awk can actually use the correct value for $i in the first script when it is enclosed in single quotes? I previously thought that single quotes kill any and all special meaning. This is as literal as you can get? How is the expansion working correctly in this case? Is there something special about using the / /, which is specific to regex?

Thanks.

sag47 07-29-2011 01:31 AM

First off ` /= '. A back tick (`) which is part of the tilde (~) key above the tab key is not a single quote ('). You are right in saying that single quotes change the meaning of a command where echo "$PATH" and echo '$PATH' give two different outputs.

I'm no awk expert but I don't believe you can simply pipe the output of a command like that from within awk. To execute commands you have to use the system function for example system("date"). As for the rest I'll defer someone else who would know better.

By the way in your awk command the $i is not enclosed by single quotes. It is outside of them. Below I have highlighted the quoted text.

awk 'BEGIN{FS="\n"; RS="++++++++++"} /'$i'/ {print $0}' log_file >/tmp/alert

You might be able to do something like this.
Code:

#!/bin/bash
awk 'BEGIN{FS="\n"; RS="++++++++++"} /'`date +%F`'/ {print $0}' log_file >/tmp/alert
mail -s "mydata" root@localhost < /tmp/alert

or even better since there's no tmp file
Code:

awk 'BEGIN{FS="\n"; RS="++++++++++"} /'`date +%F`'/ {print $0}' log_file | mail -s "mydata" root@localhost

catkin 07-29-2011 03:29 AM

Quote:

Originally Posted by sag47 (Post 4428239)
I'm no awk expert but I don't believe you can simply pipe the output of a command like that from within awk. To execute commands you have to use the system function for example system("date").

It might depend on the version of awk. It is part of at least the current GNU awk as described here.

catkin 07-29-2011 03:40 AM

Quote:

Originally Posted by Lagos (Post 4428128)
why wouldn't the following work?

Code:

awk 'BEGIN{FS="\n"; RS="++++++++++"; "date +F%"|getline dateVal} /dateVal/ {print $0}' log_file >/tmp/alert

/dateVal/ looks for exactly that, without substituting the value of dateVal. If you want to use a variable value as a regular expression then awk's dynamic regexp provisions apply. The code would be something like (not tested, spread over several lines and indented for legibility)
Code:

awk '
    BEGIN {
        FS = "\n";
        RS = "++++++++++";
        "date +F%" | getline dateVal
    }

    $0 ~ dateVal { print $0 }
' \
log_file >/tmp/alert


Lagos 07-29-2011 08:55 AM

Thank you everyone for your timely replies. I really appreciate it.

Lagos 07-29-2011 09:27 AM

Quote:

Originally Posted by sag47 (Post 4428239)
First off ` /= '. A back tick (`) which is part of the tilde (~) key above the tab key is not a single quote ('). You are right in saying that single quotes change the meaning of a command where echo "$PATH" and echo '$PATH' give two different outputs.

I'm no awk expert but I don't believe you can simply pipe the output of a command like that from within awk. To execute commands you have to use the system function for example system("date"). As for the rest I'll defer someone else who would know better.

By the way in your awk command the $i is not enclosed by single quotes. It is outside of them. Below I have highlighted the quoted text.

awk 'BEGIN{FS="\n"; RS="++++++++++"} /'$i'/ {print $0}' log_file >/tmp/alert

You might be able to do something like this.
Code:

#!/bin/bash
awk 'BEGIN{FS="\n"; RS="++++++++++"} /'`date +%F`'/ {print $0}' log_file >/tmp/alert
mail -s "mydata" root@localhost < /tmp/alert

or even better since there's no tmp file
Code:

awk 'BEGIN{FS="\n"; RS="++++++++++"} /'`date +%F`'/ {print $0}' log_file | mail -s "mydata" root@localhost

cool. this works. so, looking at the color coding above `date +%F` is outside the quotes as well. if this is the case, how do we get away with the syntax? shouldn't awk just choke?

Lagos 07-29-2011 09:29 AM

Quote:

Originally Posted by catkin (Post 4428285)
/dateVal/ looks for exactly that, without substituting the value of dateVal. If you want to use a variable value as a regular expression then awk's dynamic regexp provisions apply. The code would be something like (not tested, spread over several lines and indented for legibility)
Code:

awk '
    BEGIN {
        FS = "\n";
        RS = "++++++++++";
        "date +F%" | getline dateVal
    }

    $0 ~ dateVal { print $0 }
' \
log_file >/tmp/alert


..this seems to be the most legible in terms of readability ***and** logic. thank you.

catkin 07-29-2011 09:58 AM

Quote:

Originally Posted by Lagos (Post 4428535)
cool. this works. so, looking at the color coding above `date +%F` is outside the quotes as well. if this is the case, how do we get away with the syntax? shouldn't awk just choke?

bash substitutes the output of date +%F for `date +%F` before awk sees it. So, for example, awk sees (using colour to identify individual "words" as given to awk)
Code:

awk BEGIN{FS="\n"; RS="++++++++++"} /2011-07-29/ {print $0} log_file
EDIT: BTW, you may prefer to use $( ... ) instead of ` ... `. It is functionally superior in complex cases but more importantly it is obviously not a single quoted string which the ` .. ` form can be mistaken for.

Lagos 07-29-2011 10:10 AM

Quote:

Originally Posted by catkin (Post 4428566)
bash substitutes the output of date +%F for `date +%F` before awk sees it. So, for example, awk sees (using colour to identify individual "words" as given to awk)
Code:

awk BEGIN{FS="\n"; RS="++++++++++"} /2011-07-29/ {print $0} log_file
EDIT: BTW, you may prefer to use $( ... ) instead of ` ... `. It is functionally superior in complex cases but more importantly it is obviously not a single quoted string which the ` .. ` form can be mistaken for.

excellent....I'm one step closer to understanding the order of operations for shell expansion ...thx

catkin 07-29-2011 10:31 AM

Quote:

Originally Posted by Lagos (Post 4428578)
excellent....I'm one step closer to understanding the order of operations for shell expansion ...thx

Yes -- it helps de-mystify the shell. More info on it here.


All times are GMT -5. The time now is 01:00 AM.