3

I have a bash script that's just a shortcut to the grep command. I call it like this:

stx -p /var/www -t 'my text'

This would run this command:

sudo grep -rinI /var/www -e 'my text'

I'm trying to add in the ability to include or exclude files with a certain extension (.css, .js, etc.). Here is the script:

#!/usr/bin/bash
#search for text in files

set -x #echo all commands

while [ -n "$1" ]; do
        case "$1" in 
                -p) path="$2" # path to start search in
                shift
                ;;  
                -t) txt="$2" # text to search for
                shift
                ;;   
                -i) inc="$2"    
                        #echo 'inc: ' $inc
                        include="--include=\*.${inc}" # file type to include
                shift
                ;;  
                -?) 
                        echo 'stx usage:'
                        echo '-p    path to search in'
                        echo '-t    text to search for'
                        exit 0
                shift
                ;;
        esac 
        shift
done


result=$(sudo grep -rinI $include "$path" -e "$txt")
echo "$result"

#       grep options:
#       r               recursive
#       i               case-insensitive
#       n               show line number   
#       I               ignore binary files
#       --include       only include files with specified extension

When I run this, for some reason it puts single quotes around the $include variable, so if I try to run this to search .js files for "my text":

stx -p /var/www -t 'my text' -i js

it produces this:

sudo grep -rinI '--include=\*.js' /var/www -e 'my text'

The single quotes around the --include*.js are breaking it. How can I stop it from inserting those quotes?

  • 2
    It's not actually putting single quotes around it. I am guessing you are seeing that from set -x. Those quotes are just there to tell you that the entire string is being interpreted literally with no word splitting being performed. – jesse_b Oct 11 '19 at 18:31
  • 1
    And the problem is probably the \ in include="--include=\*.${inc}" – muru Oct 11 '19 at 18:33
  • 2
    change the \* to *, and the grep ... $include to grep ... "$include". Someone may create a file named --include=hehe.js just to mess with people running sudo from scripts. – mosvy Oct 11 '19 at 18:42
  • 2
    @raphael75: That's because there is nothing within those strings that need to be escaped so the shell doesn't need to specify that it is being interpreted literally, because there is only one way to interpret it. – jesse_b Oct 11 '19 at 18:44
  • 1
    You seem to be re-inventing Silver Searcher aka ag, ripgrep, ack-grep, and several similar projects. Why not just use one of these instead? Spend a few hours evaluating them and comparing their pros and cons. – cas Oct 12 '19 at 3:38
6

As muru pointed out this is caused by the backslash escape being used here:

-i) inc="$2"    
  #echo 'inc: ' $inc
  include="--include=\*.${inc}" # file type to include

The * wildcard does not expand inside double quotes which means it's already being escaped (by the quotes), this means that the backslash escape will be treated literally as well.

You could change it to:

-i) include="--include=*.${2}";;

Here you can see how the backslash escape is treated in various scenarios:

$ echo \*
*
$ echo "\*"
\*
$ echo "\$"
$

In the first example it is removed after it escapes *
In the second example it is not needed to escape the * so it is left literally
In the third example it is needed to escape the $ (which can expand inside single quotes) so it is removed.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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