0

The following script demonstrates my problem, which is to determine if the sox_user_auditd_v2r -c process is running:

$ cat ./pgrep_stackexchange_sample.bash
#!/bin/bash -xv

quoted="'$@'"

#if pgrep -x -f $@ > /dev/null; then #if pgrep -x -f $quoted > /dev/null; then #if pgrep -f $quoted > /dev/null; then #if pgrep -f -- $quoted > /dev/null; then #if pgrep -x $quoted > /dev/null; then if pgrep -x -- $quoted > /dev/null; then echo "Process '$@' is already running." exit 0 else echo "Process '$@' is not running. Starting it..." if ! "$@" &> /dev/null; then echo "Error: Failed to start process '$@'" exit 2 fi echo "Process '$@' started successfully" exit 0 fi

Namely, when I run it like so ./pgrep_stackexchange_sample.bash sox_user_auditd_v2r -c, pgrep would misbehave and throw an error:

+ pgrep -x -- '\'\''sox_user_auditd_v2r' '-c\'\'''
Usage: pgrep [-flvx] [-d DELIM] [-n|-o] [-P PPIDLIST] [-g PGRPLIST] [-s SIDLIST]
        [-u EUIDLIST] [-U UIDLIST] [-G GIDLIST] [-t TERMLIST] [PATTERN]

Namely, pgrep considered the -c, which should be part of the regex to be checked, as an argument for pgrep.

--

Full run output:

$ ./pgrep_stackexchange_sample.bash sox_user_auditd_v2r -c
#!/bin/bash -xv

quoted="'$@'"

  • quoted=''''sox_user_auditd_v2r -c''''

#if pgrep -x -f $@ > /dev/null; then #if pgrep -x -f $quoted > /dev/null; then #if pgrep -f $quoted > /dev/null; then #if pgrep -f -- $quoted > /dev/null; then #if pgrep -x $quoted > /dev/null; then if pgrep -x -- $quoted > /dev/null; then echo "Process '$@' is already running." exit 0 else echo "Process '$@' is not running. Starting it..." if ! "$@" &> /dev/null; then echo "Error: Failed to start process '$@'" exit 2 fi echo "Process '$@' started successfully" exit 0 fi

  • pgrep -x -- ''''sox_user_auditd_v2r' '-c''''

Usage: pgrep [-flvx] [-d DELIM] [-n|-o] [-P PPIDLIST] [-g PGRPLIST] [-s SIDLIST] [-u EUIDLIST] [-U UIDLIST] [-G GIDLIST] [-t TERMLIST] [PATTERN]

  • echo 'Process '''sox_user_auditd_v2r' '-c''' is not running. Starting it...'

Process 'sox_user_auditd_v2r -c' is not running. Starting it...

  • sox_user_auditd_v2r -c
  • echo 'Process '''sox_user_auditd_v2r' '-c''' started successfully'

Process 'sox_user_auditd_v2r -c' started successfully

  • exit 0

Can anyone suggest what would be the correct $quoted that will allow pgrep to work as expected?

Edit 1:

Trying to implement @ilkkachu answer doesn't seem to make pgrep behave. The -c is still considered as an argument by pgrep:

$ ./pgrep_stackexchange_sample.bash sox_user_auditd_v2r -c
#!/bin/bash -xv

quoted="$*"

  • quoted='sox_user_auditd_v2r -c'

#if pgrep -x -f $@ > /dev/null; then #if pgrep -x -f $quoted > /dev/null; then #if pgrep -f $quoted > /dev/null; then #if pgrep -f -- $quoted > /dev/null; then #if pgrep -x $quoted > /dev/null; then if pgrep -x -f $quoted > /dev/null; then echo "Process '$@' is already running." exit 0 else echo "Process '$@' is not running. Starting it..." if ! "$@" &> /dev/null; then echo "Error: Failed to start process '$@'" exit 2 fi echo "Process '$@' started successfully" exit 0 fi

  • pgrep -x -f sox_user_auditd_v2r -c

pgrep: invalid option -- 'c' Usage: pgrep [-flvx] [-d DELIM] [-n|-o] [-P PPIDLIST] [-g PGRPLIST] [-s SIDLIST] [-u EUIDLIST] [-U UIDLIST] [-G GIDLIST] [-t TERMLIST] [PATTERN]

  • echo 'Process '''sox_user_auditd_v2r' '-c''' is not running. Starting it...'

Process 'sox_user_auditd_v2r -c' is not running. Starting it...

  • sox_user_auditd_v2r -c
  • echo 'Process '''sox_user_auditd_v2r' '-c''' started successfully'

Process 'sox_user_auditd_v2r -c' started successfully

  • exit 0

  • 1
    Shouldn't simply pgrep -x -- "$@" work, without your trying to take care of the quoting yourself? (The -- should tell pgrep already that everything that follows is not to be read as an option.) – DonHolgo Feb 15 '23 at 19:06
  • 1
    @DonHolgo, "$@" would expand each argument to the script as separate arguments to pgrep, while I think they'd want to join them (pgrep -- sox -c vs. pgrep -- "sox -c"). So "$*" instead. (Passing through the scalar assignment var="$@" forces joining even though that's not what "$@" is for.) Giving multiple patterns to pgrep seems to be an error in some versions, and in others it looks for processes matching any of the patterns. And looking for just -c seems odd. – ilkkachu Feb 15 '23 at 19:27
  • See Edit 1 in the question ( @DonHolgo, @ilkkachu ) – boardrider Feb 15 '23 at 19:30
  • This is a dupe of your previous question. – cas Feb 16 '23 at 11:04

2 Answers2

2
quoted="\'$@\'"

This concatenates the positional parameters (arguments to the script), joined with spaces, and adds those backslashes and single quotes at the start and end. So you get e.g. \'sox_user_auditd_v2r -c\'

pgrep -x -- $quoted

This splits the string on spaces, forming multiple fields that end up as arguments to pgrep, so you get the arguments \'sox_user_auditd_v2r and -c\', as if you ran

pgrep -x -- "\'sox_user_auditd_v2r" "-c\'"

What that does, probably depends on the version of pgrep. The -- should make that -c\' not be taken as an option, but as a pattern to look for. But it looks like not all versions of pgrep accept multiple patterns, so perhaps that is what the one you have is complaining about. (Anyway those backslashes and single quotes probably aren't that common in argument strings, so that's likely not what you want.)


Instead, remove the quotes from the data, and put them around the variable expansion. Also, you should probably use "$*" for joining the arguments, as it's meant for that, while "$@" is mostly meant for expanding the positional parameters separately. It's just that in a scalar assignment, expanding to multiple fields/arguments doesn't work, so they do a similar thing, but "$*" is clearer on the intent.

I think you also want pgrep -f to match against the full argument list, and not just the process name. So something like this:

#!/bin/bash
key="$*"
pgrep -x -f "$key"

See:

ilkkachu
  • 138,973
-1

Based on @ilkkachu excellent answer (and a debugging session with GC), the following script has pgrep working as expected:

#!/bin/bash

This script checks if a process is running and starts it if it's not.

If the process is already running, the script exits with exit code 0.

If the process was restarted by the script, the script exits with exit code 0.

If the process fails to start, the script exits with exit code 2.

If the first argument is "-h" or "--help", the script prints a help message and exits with exit code 10.

if pgrep -x -f "$" > /dev/null; then echo "Process '$' is already running." exit 0 else echo "Process '$' is not running. Starting it..." if ! $ &> /dev/null; then echo "Error: Failed to start process '$@'" exit 2 fi echo "Process '$*' started successfully" exit 0 fi