8

I want to add this command grep -co '\b5\b' $INFILE in a bash script. The problem is that instead of 5 i want to use a variable in its place so i write:

V=`grep -co '\b$L\b' $INFILE`

but it does not work since the $ is used to describe internally the end of line in grep. How can i make it work? Is there an escape sequence for $ to make it use its bash meaning of the value of a variable?

2 Answers 2

13

Use " instead of ' to allow expansion of your $L variable.

Sign up to request clarification or add additional context in comments.

2 Comments

For reference, gnu.org/software/bash/manual/bashref.html#Single-Quotes (And the section below, which is Double-Quotes)
Also, inside double quotes if you do want to specify end-of-line, escape the dollar sign grep "foo\$" (although that's not strictly necessary if there's nothing but a quote after the dollar sign).
0

I regularly encounter this issue: accurately using grep or rg (ripgrep) to find $variables.

Conclusion (best practice, based on following experiments):

  • Use single quotes, and \-escape the $

    '\$variable'

    not

    "\$variable' or unescaped "$variable"

## ----------------------------------------
[victoria@victoria]$ which grep
  /usr/bin/grep

[victoria@victoria]$ grep --version
  grep (GNU grep) 3.7
  ...

[victoria@victoria]$ which rg
  /usr/bin/rg

[victoria@victoria]$ rg --version
  ripgrep 13.0.0
  ...

[victoria@victoria]$

## ----------------------------------------
## RIPGREP (rg):
## -------------

## ----------------------------------------
## -i : ignore case
## -n : show matching lines, line numbers
## -l : show matching files
## -R : search recursively (grep)

## TRUE: 8 files matching '\$username':
[victoria@victoria]$ rg * --color=always -il -e '\$username' | wc -l
  8

## TRUE: In those 8 files, 34 lines matching '\$username':
[victoria@victoria]$ rg * --color=always -in -e '\$username' | wc -l
  34

## First 5 matching lines:
[victoria@victoria]$ rg * --color=always -in -e '\$username' | head -n5

  sql/old/mysql-pg_auth-create_tables-2022.05.28.php:13:$username = "root";

  sql/old/mysql-pg_auth-create_tables-2022.05.28.php:25:
  $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);

  sql/old/mysql-pg_auth-create_tables-2022.05.28.php:58:
  $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);

  src/auth.php:23:* @param string $username

  src/auth.php:36:function register_user(string $email, string $username, 
  string $password, string $activation_code, int $expiry = 1 * 24  * 60 *
  60, bool $is_admin = false): bool

## ----------------------------------------
## single quotes, unescaped $ - no matching lines
## (FALSE - there are 34 lines matching: $username):
[victoria@victoria]$ rg * --color=always -in -e '$username' | wc -l
  0

## ----------------------------------------
## double quotes, \-escaped $ - no matching files
## (FALSE - there are 8 files matching: $username):
[victoria@victoria]$ rg * --color=always -il -e "\$username" | wc -l
  0

## ----------------------------------------
## FALSE - as shown in following query ...
[victoria@victoria]$ rg * --color=always -il -e "$username" | wc -l
  154

## ... unescaped "$username" falsely matching lines:
[victoria@victoria]$ rg * --color=always -in -e "$username" | head -n5

  vendor/autoload.php:1:<?php
  vendor/autoload.php:2:
  vendor/autoload.php:3:// autoload.php @generated by Composer
  vendor/autoload.php:4:
  vendor/autoload.php:5:if (PHP_VERSION_ID < 50600) {

[victoria@victoria]$

## ----------------------------------------
## GREP
## ----

## grep is somewhat more forgiving:

## unquoted variable name (misses matches;
## should be 8 matching files):
[victoria@victoria]$ grep --color=always -ilR $username * | wc -l
  3

## "$username" - FALSE (way too many files):
[victoria@victoria]$ grep --color=always -ilR "$username" * | wc -l
  442

## '$username' - TRUE number of matched files:
[victoria@victoria]$ grep --color=always -ilR '$username' * | wc -l
  8

[victoria@victoria]$ grep --color=always -inR '$username' * | head -n5

  docs-private/_readme-victoria.txt:159: function register_user(string 
  $email, string $username, string $password, string $activation_code,
  int $expiry = 1 * 24  * 60 * 60, bool $is_admin = false): bool

  docs-private/_readme-victoria.txt:166:
  $statement->bindValue(':username', $username);

  sql/create_drop_mysql_tables.php:20:$username = "root";

  sql/create_drop_mysql_tables.php:35:    $conn = new 
  PDO("mysql:host=$servername;dbname=$dbname", $username, $password);

  sql/create_drop_mysql_tables.php:72:    $conn = new 
  PDO("mysql:host=$servername;dbname=$dbname", $username, $password);

## '\$username' - TRUE number of matched files:
[victoria@victoria]$ grep --color=always -ilR '\$username' * | wc -l
  8

## "\$username" = TRUE number of matched files:
[victoria@victoria]$ grep --color=always -ilR "\$username" * | wc -l
  8

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.