3

This question already has an answer here:

In my bash script I have a variable that I am trying to pass to a pattern to search for using awk. However what I expected to happen is not working. I have the following text file (text.txt):

-----------
Task:           a
 (some info)
  ....
------------
Task:           b 
 (some info)
  ....
------------
Task:           c
 (some info)
  ....
------------

My script has the following:

letter=a
awk -v var="$letter" '/Task .* \var/' RS='-+' text.txt

When I do this however I get nothing but if I do the following:

awk '/Task .* a/' RS='-+' text.txt

I get what I expect:

Task:           a
 (some info)
  ....

NOTE: I need to pass it as a variable because I have a loop that is constantly changing the variable and that's what I am trying to look for. I'd rather use awk since that what I am most familiar with but I am not opposed to hearing other suggestions such as sed or grep.

marked as duplicate by techraf, Wildcard, HalosGhost, sam, Satō Katsura Nov 25 '16 at 8:23

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 1
    Have you tried searching for a solution as this is asked a lot. Try -v var="$var" – 123 Jul 16 '15 at 13:36
  • I have and I tried using the -v option and that still was giving me an issue. – pdm Jul 16 '15 at 13:38
  • 1
    Probably best to post the problem with that then. as thats how you pass awk variables – 123 Jul 16 '15 at 13:39
  • Is "some info" a fixed number of lines or can it vary? – glenn jackman Jul 16 '15 at 13:43
  • It will vary that why I am using the RS separator – pdm Jul 16 '15 at 13:44
8

You could pass the whole pattern to awk

letter=a
awk -v pattern="Task .* $letter" -v RS='-+' '
    $0 ~ pattern
' text.txt

or construct the pattern as a string in awk

letter=a
awk -v ltr="$letter" -v RS='-+' '
    BEGIN {pattern = "Task .* " ltr}
    $0 ~ pattern
' text.txt

Since awk variables are not prefixed with $, you can't embed them inside a /regex constant/ -- it's just text in there.

(It's my preference to put all awk variables at the front with -v)

  • why not $1 == "Task:" && $2 == ltr ? – Archemar Jul 16 '15 at 13:45
  • 1
    Pedantically, ~ is the regular expression matching operator: string ~ regex -- gnu.org/software/gawk/manual/html_node/… – glenn jackman Jul 16 '15 at 14:00
  • 1
    One correction, test and [ are equivalent, and [[ has some different behaviour. The bash =~ works with [[ but not [ or test. – glenn jackman Jul 16 '15 at 17:55
  • 1
    @syntaxerror - one needn't insist on using a very ancient bash to render that statement untrue - there are many shells in which [[ ... =~ ... ]] is invalid syntax - and all of these that I'm aware of are far faster in practically every respect than any version of bash I've ever used. In any case, ~ is the C-language bitwise NOT (and so also performs that function in shell $(( arithmetic expansions ))) and I've always found the portable case construct to be both more useful and more readable than [[ ... =~ ... ]] anyway, (especially because it's faster, too). – mikeserv Jul 16 '15 at 18:09
  • 1
    If you just want the first one: $0 ~ pattern {print; exit} – glenn jackman Jul 20 '15 at 14:27
3

Your best choice maybe passing variable through environment:

letter=a
p="Task: *$letter" awk -v RS='-+' '$0 ~ ENVIRON["p"]' <file

or:

p="Task: *a" awk -v RS='-+' '$0 ~ ENVIRON["p"]' <file

Using -v var=value, awk will expand escape sequences in value. If you want to pass data as-is to awk from shell, -v var="$shell_var" is not reliable.

Using ENVIRON (or ARGV) is a more reliable since when awk doesn't expand escape sequences in it.

  • @mikeserv: Yep, included the explanation in my answer. – cuonglm Jul 16 '15 at 17:17
  • In POSIX awk, can you provide a regex for the RS variable? – glenn jackman Jul 16 '15 at 18:00
  • @glennjackman: No, POSIX made it unspecified. I edited my answer to prevent confusing. – cuonglm Jul 16 '15 at 18:10

Not the answer you're looking for? Browse other questions tagged or ask your own question.