Search code examples
bashgrepevalgetopts

grep doesn't take getopts


There is a directory:

.
├── file4.txt
├── file5.yml
├── txt
│   ├── file1.txt
│   ├── file2.txt
│   └── file3.txt
└── yml
└── file6.yml

Some files contain a word hello:

>> grep -r 'hello' .

  ./file4.txt:hello
  ./yml/file6.yml:hello
  ./txt/file1.txt:hello
  ./txt/file2.txt:hello
  ./file5.yml:hello

And now I want to write a script, which would search for hello in different locations and files, i.e.:

$ grep -EHori --exclude-dir={txt,yml} --include="*.txt" 'hello' .
  ./file4.txt:hello
$ grep -EHori --exclude-dir={txt,yml} --include="*.yml" 'hello' .
  ./file5.yml:hello
$ grep -EHori --exclude-dir={yml} --include="*.yml" 'hello' .
  ./yml/file6.yml:hello
  ./file5.yml:hello
$ grep -EHori --exclude-dir={txt} --include="*.yml" 'hello' .
  ./yml/file6.yml:hello
  ./file5.yml:hello
$ grep -EHori --exclude-dir={txt} --include="*.txt" 'hello' .
  ./file4.txt:hello
  ./txt/file1.txt:hello
  ./txt/file2.txt:hello

I have:

#!/bin/bash

exclude_path="txt"
file_types="*.txt"
include_path="./"
check_path="./"

while getopts ":e:t:i:p" opt; do
    case $opt in
         e)
            exclude_path="${OPTARG}"
            ;;
         t)
            file_types="${OPTARG}"
            ;;
         i)
            include_path="${OPTARG}"
            ;;
         p)
            check_path="${OPTARG}"
    esac
done

result=$(grep -EHori --exclude-dir=$exclude_path \
    --include=$file_types 'hello' "$check_path")
echo $result

But, it doesn't work with multiple values for exclude_path and include_path , i.e.:

grep -r --exclude-dir={dir1,dir2,dir3} --include={type1,type2,type3} keyword /path/to/search

Also if I use -p, grep complains No such file.

$ ./grep.sh
  ./file4.txt:hello
$ ./grep.sh -t *.yml
  ./file5.yml:hello
$ ./grep.sh -p yml -t *.yml
  grep: : No such file or directory
$ ./grep.sh -t *txt,*.yml

I do need to save the result as a variable since I work with it further. I think I should used eval wtih grep and escape variables, but I'm not sure.


Solution

  • You have a typo in your getopt statement:

    while getopts ":e:t:i:p" opt; do
    

    should be

    while getopts ":e:t:i:p:" opt; do
    

    without the last : p doesn't take any argument, so when you typed -p yml it executed grep ... '' cause check_path="" cause OPTARG was empty for p:

    $ bash -x ./grep.sh -p yml -t '*.yml'
    ...
    ++ grep -EHori --exclude-dir=txt '--include=*.txt' hello ''
    grep: : No such file or directory
    ...
    

    The fixed script outputs:

    $ ./grep.sh -p yml -t '*.yml'
    yml/file6.yml:hello
    

    Side note: Remember to properly enclose your arguments, typing ./grep.sh -p yml -t *.yml will execute ./grep.sh -p yml -t file5.yml cause * gets expanded by bash. Probably you meant to enclose it in ', otherwise ./grep.sh -p yml -t *.yml returns only empty line (from the echo), because file5.yml is not inside yml directory.