1

This answer about -- gives a lot of good information about using -- in POSIX shells and this answer about passing all arguments to a script led to the following function:

my_echo()
{
    set -x
    echo $@ " " \"$@\"
    echo `ps | grep -- "$@" | grep -v grep | awk '{ print $1 }'` 2>/dev/null
    set +x
}

my_echo logread -f

I'm writing this script for OpenWRT. The output from ash shows

+ echo logread -f   "logread -f"
logread -f   "logread -f"
+ ps
+ grep -v grep
+ awk { print $1 }
+ grep -- logread -f
grep: -f: No such file or directory
+ echo

+ set +x

Huh...the quotes I added to the grep command are gone (logread -f is left unquoted).

I tried this function in bash

+ echo logread -f ' ' '"logread' '-f"'
logread -f   "logread -f"
++ ps
++ grep --color=auto -- logread -f
++ grep --color=auto -v grep
++ awk '{ print $1 }'
grep: -f: No such file or directory
+ echo

+ set +x

Interesting...maybe my arguments are being parsed separately? To test this theory, I tried:

my_echo "logread -f"

Bash Output:

+ echo logread -f ' ' '"logread' '-f"'
logread -f   "logread -f"
++ ps
++ grep --color=auto -- 'logread -f'
++ grep --color=auto -v grep
++ awk '{ print $1 }'
+ echo

+ set +x

The output of the echo command didn't change (the set version or the actual output but logread -f now seems to be treated as if in double quotes. So...I got lucky because I misinterpreted set's translation of my commands. BUT, my function works now.

Ash Output:

+ echo logread -f   "logread -f"
logread -f   "logread -f"
+ ps
+ grep -v grep
+ awk { print $1 }
+ grep -- logread -f
+ echo

+ set +x

And now I'm getting what I expected. It turns out, running my_echo with arguments passed in double quotes (single argument) is the same as

my_echo_new()
{
    echo `ps | grep -- "$1" | grep -v grep | awk '{ print $1 }'` 2>/dev/null
}

my_echo_new "logread -f"

So...it sure seems like the issue is with working with multiple arguments. What is going on here? Is this a result of the ` or the result of the function call or something else? Why do I need double quotes in both places?

3

"$@" expands to a list of quoted strings. If you pass the two arguments logread and -f to your function, then "$@" would expand to two strings.

Running grep -- "$@" would therefore expand to grep -- logread -f, which means "grep for logread in the file called -f".

Would you want to pass separate arguments rather than a single string, then use "$*" to expand the arguments to a single quoted string.

grep -e "$*"

would expand to grep -e "logread -f". The positional parameters would be delimited by the first character in $IFS when using "$*" (by default, this is a space). Also note that using either $* or $@ unquoted does not make sense.

As an aside, I would probably opt for using pgrep/pkill here:

if ! pgrep -xf "$*" >/dev/null; then
    printf 'No process matches "%s" exactly\n' "$*"
fi

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.