In Mac, how to do `tail -f --pid` to terminate after process exit like Linux?

tail command in current Linux has --pid option to terminate after certain process id, while tail under MAC OSX doesn't have the same option. e.g. tail -f --pid=<process_pid> can terminate tail mode if process_pid terminated.

So how can we get the same result as Linux tail -f --pid?


Solution 1:

There are perhaps several possible ways you can accomplish that.

First solution (easiest): How to replace Mac OS X utilities with GNU core utilities?

Follow the above and install gnu tail. You can then possibly have a function or alias of tail to gtail. like

alias tail=gtail

or even a Bash function:

tail(){
  command gtail "$@"
}

or just simply call gtail altogether instead of BSD tail

Second solution: The second way of doing that would be to make your own function, which you can add in your bash_profile or make a script, whatever suits you. In this script, all that we are doing is just to check if the PID exists or not. If it exists then we tail otherwise we exit with return code 1.

_tail(){
  # usage _tail -f <file> <pid>
  function _tail::trap() {
    trap - SIGTERM && kill -- -$$
  }
  local FILE="$1"
  local PID="$2"
  if ps -p "$PID" > /dev/null; then
    trap _tail::trap SIGINT
    command tail -f "${FILE}" &
    local pid=$!
    disown # Optional: if you want to supress the kill SIGINT message
    local run=true
    while ${run}; do
      if ! $(ps -p ${PID} > /dev/null); then
        kill -9 ${pid} > /dev/null 2>&1
        run=false
      fi
    done
  else
    return 1
  fi
}

Now, you can call this function like _tail <file-to-tail> <pid>, which will do exactly same thing as gtail -f <file-to-tail> --pid=<pid>

However, if you want, you can extend it further and make it same syntaxt as gnu tail by adding another function called tail and sourcing it in .bash_profile or in your path as executable.

tail(){
  # usage: tail -f <file> --pid=<pid>
  local fFlag="$1"
  local FILE="$2"
  local PIDARGS="$3"
  local PIDARG="$(echo ${PIDARGS} | cut -d '=' -f1)"
  local PID="$(echo ${PIDARGS} | cut -d '=' -f2)"
  if [[ "$fFlag" == "-f" ]] && [[ -f "${FILE}" ]] && \
    [[ "${PIDARG}" == "--pid" ]] && [[ $(ps -p "${PID}") ]]; then
    _tail "${FILE}" "${PID}"
  else
    command tail "$@"
  fi
}

[[ "${BASH_SOURCE[0]}" == "$0" ]] && tail "$@"

enter image description here