7

How can I use a variable string in a regular expressions?

while read line
do
    if [[ line =~ *"$key"* ]]; then
        echo line
    fi
done < "$filename"

$key is a string variable and I want to print all the lines that has the value of $key.

4
  • 1
    Are you sure about that pattern? *$key* would be quite the odd pattern to match if $key were something like ^foo or foo$, resulting in a pattern of *^foo* or *foo$*.
    – DopeGhoti
    Jan 3, 2014 at 18:17
  • 1
    @DopeGhoti The question is about why the script doesn't work, and those errors you fixed in your edit are why it doesn't. Editing the question to fix the errors actually renders the question useless...
    – derobert
    Jan 3, 2014 at 18:23
  • My apologies for the faux-pas.
    – DopeGhoti
    Jan 3, 2014 at 18:24
  • @DopeGhoti No problem. Edits to fix errors like that are generally welcome in answers. You probably want to be wary of editing code in questions, as the error might be the cause of the problem. Of course, feel free to fix grammar, spelling, formatting, etc.
    – derobert
    Jan 3, 2014 at 18:28

2 Answers 2

9

You've made a few mistakes there. Here's your script corrected:

while read line
do
    if [[ "$line" =~ $key ]]; then
        echo $line
    fi
done < "$filename"

Though it seems it could be replaced with a simple grep:

grep "$key" "$filename"
6
  • grep "$key" "$filename" is not exactly equivalent, since in this context, $key is interpreted as a BRE. Use -F to avoid this.
    – Chris Down
    Jan 3, 2014 at 18:14
  • the grep works fine but the while loop isn't doing anything, thanks though! Jan 3, 2014 at 18:23
  • 1
    @user2798694: that's what Janos meant ^^ : no longer use the "while ..... done", but instead just use: grep "$key" "$filename" . grep will only output lines matching $key in the file $filename, which seems to be what you were trying to do? [unless you wanted to do additionnal things for each matched lines?] Jan 3, 2014 at 18:27
  • There's a performance loss by using grep rather than the builtin.
    – Will
    Jun 15, 2015 at 19:08
  • 2
    This example no longer works with Bash versions >= 4.0. If the right-hand side of the =~ operator is quoted, variable expansion is not performed.
    – Bklyn
    Feb 9, 2017 at 18:45
1

First, whenever you're using the value of a variable, you need to write $line.

Also, note that read line strips off leading and trailing whitespace, and allows the sequence backslash-newline as a line continuation. To retain whitespace, use IFS= read. To avoid treating \ specially, use read -r. You can of course combine the two as IFS= read -r.

What do you want to test exactly? If you want to test that the line is exactly $key (except for whitespace unless you use IFS= read), use the == operator, and make sure to put $key in double quotes.

if [[ $line == "$key" ]]; then …

If you want to test that the line contains $key (so for example if the value of key is fu*bar then hellofu*bar and fu*barqux match, but fuubar and gu*bar don't), then use the == operator and again make sure to put $key in double quotes. The right-hand side of the == operator is a shell wildcard pattern; putting the variable in double quotes causes it to be treated literally.

if [[ $line == *"$key"* ]]; then …

If you want to treat $key as a wildcard pattern, so that if $key is fu*bar then the line can be fubar or fuqwebar but not fbar or afubar, then leave off the double quotes:

if [[ $line == $key ]]; then …

If you only want part of the line to match, allowing things like afubar:

if [[ $line == *$key* ]]; then …

Use the regular expression match operator =~ if you want to have an extended regular expression on the right-hand side. A regular expression can match part of the line; if you want to match the whole line, put ^ at the beginning of the regex and $ at the end. For example, [[ $line == *"$key"* ]] is equivalent to [[ $line =~ "$key" ]] while [[ $line == "$key" ]] is equivalent to [[ $line =~ ^"$key"$ ]].

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .