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
4
  • 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.) Commented Feb 15, 2023 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. Commented Feb 15, 2023 at 19:27
  • See Edit 1 in the question ( @DonHolgo, @ilkkachu ) Commented Feb 15, 2023 at 19:30
  • This is a dupe of your previous question. Commented Feb 16, 2023 at 11:04

2 Answers 2

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:

2
  • Thanks, @ilkkachu. See Edit 1 in my question. Commented Feb 15, 2023 at 19:27
  • @boardrider, note the quotes around the variable expansion. "$key", not $key. (or "$quoted" in your script, just that I think that's a rather misleading a name). See also Why does my shell script choke on whitespace or other special characters? Commented Feb 15, 2023 at 19:31
-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
2
  • What useful info does this add that the referred answer doesn't have? Commented Feb 15, 2023 at 21:37
  • Also if you're going to start the process, you should use "$@" Commented Feb 15, 2023 at 21:38

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.