View on GitHub

bash-funk

bash-funk is a collection of useful commands for Bash 3.2 or higher.

Bash-Funk “processes” module

The following commands are available when this module is loaded:

  1. -get-child-pids
  2. -get-parent-pid
  3. -get-toplevel-parent-pid
  4. -kill-childs
  5. -kill-listener
  6. -test-all-processes

License

SPDX-FileCopyrightText: © Vegard IT GmbH (https://vegardit.com)
SPDX-License-Identifier: Apache-2.0

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

-get-child-pids

Usage: -get-child-pids [OPTION]... [PARENT_PID]

Recursively prints all child PIDs of the process with the given PID.

Parameters:
  PARENT_PID (default: '$$', integer: 0-?)
      The process ID of the parent process. If not specified the PID of the current Bash process is used.

Options:
    --printPPID
        Specifies to also print the PID of the parent process.
    -----------------------------
    --help
        Prints this help.
    --tracecmd
        Enables bash debug mode (set -x).
    --selftest
        Performs a self-test.
    --
        Terminates the option list.

Implementation:

local childPids # intentional declaration in a separate line, see http://stackoverflow.com/a/42854176
childPids=$(command ps -o pid --no-headers --ppid $_PARENT_PID 2>/dev/null | sed -e 's!\s!!g'; exit ${PIPESTATUS[0]})
if [[ $? != 0 ]]; then
   echo "No process with PID ${1} found"'!'
   return 1
fi
for childPid in $childPids; do
   -get-child-pids --printPPID $childPid
done
if [[ $_printPPID ]]; then
   echo $_PARENT_PID
fi

-get-parent-pid

Usage: -get-parent-pid [OPTION]... [CHILD_PID]

Prints the PID of the parent process of the child process with the given PID.

Parameters:
  CHILD_PID (default: '$$', integer: 0-?)
      The process ID of the child process. If not specified the PID of the current Bash process is used.

Options:
    --help
        Prints this help.
    --tracecmd
        Enables bash debug mode (set -x).
    --selftest
        Performs a self-test.
    --
        Terminates the option list.

Implementation:

local parentPid # intentional declaration in a separate line, see http://stackoverflow.com/a/42854176
parentPid=$(cat /proc/${_CHILD_PID}/stat 2>/dev/null | awk '{print $4}'; exit ${PIPESTATUS[0]})
if [[ $? != 0 ]]; then
   echo "No process with PID ${_CHILD_PID} found"'!'
   return 1
fi
echo $parentPid

-get-toplevel-parent-pid

Usage: -get-toplevel-parent-pid [OPTION]... [CHILD_PID]

Prints the PID of the top-level parent process of the child process with the given PID.

Parameters:
  CHILD_PID (default: '$$', integer: 0-?)
      The process ID of the child process. If not specified the PID of the current Bash process is used.

Options:
    --help
        Prints this help.
    --tracecmd
        Enables bash debug mode (set -x).
    --selftest
        Performs a self-test.
    --
        Terminates the option list.

Implementation:

local pid=$_CHILD_PID
while [[ $pid != 0 ]]; do
   pid=$(-get-parent-pid ${pid})
   if [[ $? != 0 ]]; then
      echo $pid
      return 1
   fi
done
echo ${pid}

-kill-childs

Usage: -kill-childs [OPTION]... [PARENT_PID]

Sends the TERM(15) signal to all child processes of the process with the given PID.

Parameters:
  PARENT_PID (default: '$$', integer: 0-?)
      The process ID of the parent process. If not specified the PID of the current bash process is used.

Options:
-s, --signal VALUE (integer: 1-64)
        The signal to be send, eg. 9=KILL or 15=TERM.
    -----------------------------
    --help
        Prints this help.
    --tracecmd
        Enables bash debug mode (set -x).
    --selftest
        Performs a self-test.
    --
        Terminates the option list.

Implementation:

local signal=${_signal:-15}

local childPids # intentional declaration in a separate line, see http://stackoverflow.com/a/42854176
childPids=$(-get-child-pids $_PARENT_PID)
if [[ $? != 0 ]]; then
   echo $childPids
   return 1
fi

for childPid in $childPids; do
   echo "Killing process with PID $childPid..."
   kill -s $signal $childPid 2> /dev/null || :
done

-kill-listener

Usage: -kill-listener [OPTION]... PORT

Sends the given kill signal the process listening on the given TCP port.

Requirements:
  + Command 'netstat' must be available.

Parameters:
  PORT (required, integer: 0-65535)
      TCP Port number to check.

Options:
-s, --signal VALUE (integer: 1-64)
        The signal to be send, eg. 9=KILL or 15=TERM.
    -----------------------------
    --help
        Prints this help.
    --tracecmd
        Enables bash debug mode (set -x).
    --selftest
        Performs a self-test.
    --
        Terminates the option list.

Implementation:

local signal=${_signal:-15}
if hash netstat &>/dev/null; then
   local listener=$(netstat -lantp 2>/dev/null | sed -En "s/^tcp\s+[0-9]+\s+[0-9]+ .*:$_PORT .* (-|[0-9]+\/[^ ]*)\s+$/\1/p" | uniq || :)
   if [[ $listener == "-" ]]; then
      echo "-kill-listener: Could not determine PID of processs listening on TCP port $_PORT. Try using sudo."
      return 1
   else
      echo "-kill-listener: No listening process on TCP port $_PORT found."
      return 0
   fi
else
   local listener=$(lsof -iTCP:$_PORT | sed -En "s/([^ ]+)\s+([0-9]+).*\s+/\2\/\1/p" | uniq || :)
   if [[ ! $listener ]]; then
      if [[ $EUID -eq 0 ]]; then
         echo "-kill-listener: No listening process on TCP port $_PORT found."
         return 1
      else
         echo "-kill-listener: Could not determine if a processs is listening on TCP port $_PORT. Try using sudo."
         return 1
      fi
   fi
fi

if [[ $listener ]]; then
   local pid=${listener%%/*}
   echo "-kill-listener: Sending kill signal $signal to process $process..."
   kill -$signal $pid
   return
fi

-test-all-processes

Usage: -test-all-processes [OPTION]...

Performs a selftest of all functions of this module by executing each function with option '--selftest'.

Options:
    --help
        Prints this help.
    --tracecmd
        Enables bash debug mode (set -x).
    --selftest
        Performs a self-test.
    --
        Terminates the option list.

Implementation:

-get-child-pids --selftest && echo || return 1
-get-parent-pid --selftest && echo || return 1
-get-toplevel-parent-pid --selftest && echo || return 1
-kill-childs --selftest && echo || return 1
-kill-listener --selftest && echo || return 1