0

The following code saves my_string in the file my_filename and then checks whether pattern1 and pattern2 are in the file. The first is; the second isn't.

#!/bin/bash

my_string="One two three four" 
pattern1="two three"
pattern2="two four"

my_filename="my_temp_file"

safeGrepCommand() {
    typeset command_to_run="$*"
    typeset ret_code

    # echo command_to_run=$command_to_run
    eval $command_to_run
    ret_code=$?
    if [ $ret_code != 0 ]; then
        printf "Pattern %s is not in the file %s.\n" "${my_pattern}" "${my_filename}"
        exit $ret_code
    fi
}

echo $my_string > $my_filename

grep_command1="grep --quiet ${pattern1} ${my_filename}"
safeGrepCommand "$grep_command1"

grep_command2="grep --quiet ${pattern2} ${my_filename}"
safeGrepCommand "$grep_command2"

rm -f $my_filename

I am expecting to see the output

Pattern two four is not in the file my_temp_file.

Instead I see

grep: three: No such file or directory
grep: four: No such file or directory

As you'll see if you uncomment the echo line inside the function, the problem is that the quotation marks are not seen by grep.

command_to_run=grep --quiet two three my_temp_file
command_to_run=grep --quiet two four my_temp_file

How do I get bash to pass the quotation marks to grep? Alternatively, how do I specify "two three" as a regexp with [:space] and not worry about quotation marks.

5
  • 3
    Do not stick commands in strings. If you need to do this sort of thing use an array. You cannot get this to work reliably. See mywiki.wooledge.org/BashFAQ/050 for more details and discussion. In your case this is even simpler as you can just not use grep_command1 at all and just pass the arguments to safeGrepCommand directly. (Though assigning $* to a variable will still bite you. Don't do that. Just use "$@" where you need the expansion (and you don't even need eval for that). Commented Nov 13, 2014 at 16:21
  • possible duplicate of Preserving escapes in bash arguments $@ Commented Nov 13, 2014 at 16:24
  • possible duplicate of Passing arguments to a command in Bash script with spaces Commented Nov 13, 2014 at 16:25
  • 3
    I would suggest that using eval is the opposite of "safe" Commented Nov 13, 2014 at 16:32
  • @rici Indeed. I picked the one with the highest vote count I could find quickly. Commented Nov 13, 2014 at 16:34

2 Answers 2

1

Here's one way of resending arguments in a shell function:

doit_or_complain() {
  # The arguments are captured only to show how to do it. In practice,
  # I would just use "${@}" to run the command.
  local -a command=("$@")
  "${command[@]}"
  local rc=$?
  if ((rc)); then
    echo "The command failed" >> /dev/stderr
  fi
  return $rc
}

That will work with any random arguments:

doit_or_complain grep "a  b" "./my file with spaces in its name"

If you want to pass a complicated command to the shell function, you should use an array:

theCommand=(grep "a  b" "./my file with spaces in its name")
#...
doit_or_complain "${theCommand[@]}"

Note: The function in the OP used exit $rc if the command failed. That will exit the current shell, not just the function, which might be considered a tad unexpected, if not unsafe.

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

Comments

0

Wrap the pattern variable in double quotes as

grep_command1="grep --quiet \"${pattern1}\" \"${my_filename}\""
safeGrepCommand "$grep_command1"

grep_command2="grep --quiet \"${pattern2}\" \"${my_filename}\""
safeGrepCommand "$grep_command2"

7 Comments

Thanks for your reply, but it seems something else is still wrong. If I replace "two<space>four" with "two<space><space>three" (i.e., with two spaces), I am expecting that the grep will fail. Yet after using the double quotes it succeeds. What is happening?
@Calaf its because the multiple spaces within double quotes are treated as a single space. If you want to force double space, escape the spaces as well. Which will work
@Calaf: this is not the way to go. Please see any of the answers using arrays in the linked duplicate questions, and/or read the bash faq mywiki.wooledge.org/BashFAQ/050 . (However, the problem is that you are not quoting the argument to eval.)
@nu11p01n73R I had tried that, but instead of getting "Pattern two<space><space>three is not in the file my_temp_file." I got the two lines "Pattern two is not in the file my_temp_file.\nPattern three is not in the file my_temp_file."
@rici I tried to make the question as brief as possible. This seems like a trivial exercise. Still, my use of a function was intended only for safety. How would you write it?
|

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.