Filter out invalid PIDs portably

Viewed 180

I wrote a script to fetch the Top Level Session PID, that is, the session starter, who may be a shell like bash, dash, ksh, or even systemd. The script may get a PID as a initial parameter however I need to filter it to check it is a valid integer and not something like 34fg45, -5467 and I don't want it starting with a zero like 05467.

This is a snippet of the script.

if [ "$1" != "" ]; then
    if [[ "$1" == [1-9]*([0-9]) ]]; then                <- Check for Integer; error here in non bash shell 
        if ps -p $1 -o "pid=" >/dev/null 2>&1; then
            pid=$1
        else
            echo "PID $1, no such process." >&2
            exit 1
        fi
    else
        echo "Invalid pid." >&2
        exit 1
    fi
else
    pid=$$
fi

The code runs in bash, but fails to run on dash with a syntax error:

./tspid: 16: ./tspid: Syntax error: "(" unexpected (expecting "then")

It is my understanding that

if [[ "$1" =~ ^[0-9][1-9]*$ ]]; using =~ does regular expression matching, and
if [[ "$1" == [1-9]*([0-9]) ]]; using == does pattern matching

  1. Is that right?
  2. How to transform the above expressions to run in both, non-bash as well in bash shells ?
1 Answers

Use case conditional construct. Every POSIX shell has it and unlike double brackets it doesn't look horrible.

# make sure 0-9 is literally 0 to 9
LC_COLLATE=C
# assume set -u is not in effect or $1 is set
case $1 in
('')
  # handle empty argument
  ;;
(0*|*[!0-9]*)
  # handle invalid PID (0, 042, 42a, etc.)
  ;;
(*)
  # handle valid PID
  ;;
esac
# restore LC_COLLATE if necessary
Related