Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- #Written by Manuel Iglesias. glesialo@gmail.com
- CommandName=${0##*/}
- CommandOptionString="-c"
- RunInBackgroundOptionString="-b"
- KillProcessOptionString="-k"
- ProcessFinishedOptionString="-f"
- TempDir="/tmp"
- KillProcessTimeout="1" # Max time for killed process's parent to save child process' info. '$CommandName -k ' fails if parent still running after timeout.
- KillSignal=HUP
- ########### Functions. BEGIN.
- echoE()
- {
- echo -e $* 1>&2
- return 0
- }
- Usage()
- {
- echoE "'$CommandName' can be used to launch/control a process running in background."
- echoE "Usage: '$CommandName $CommandOptionString Command [Param [Param...]]'."
- echoE "\tLaunches 'Command [Param [Param...]]' in background."
- echoE "\tOutputs background process Id. Exitcode 0 if successful."
- echoE "Usage: '$CommandName ProcessPid'."
- echoE "\tOutputs background process' info (See below)."
- echoE "\tExitcode 0 if process is valid and no longer running (Info valid)."
- echoE "\tExitcode 1 if process valid and still running (Info not valid)."
- echoE "\tExitcode non 0 if not a valid process or any other problems"
- echoE "\t (Info not valid)."
- echoE "Usage: '$CommandName $ProcessFinishedOptionString ProcessPid'."
- echoE "\tChecks if process with 'ProcessPid' Pid has finished running."
- echoE "\tExitcode 0 if process is valid and no longer running"
- echoE "\tExitcode 1 if process valid and still running."
- echoE "\tExitcode non 0 if not a valid process or any other problems."
- echoE "\tDoes not output any info."
- echoE "Usage: '$CommandName $KillProcessOptionString ProcessPid'."
- echoE "\tKills process with 'ProcessPid' Pid (Previously"
- echoE "\t launched by '$CommandName')."
- echoE "\tOutputs background process' info (See below)."
- echoE "\tExitcode 0 if valid process and killed successfully"
- echoE "\t (Or had exited already) and info read successfully."
- echoE "Background process' info:"
- echoE "\tText that when sourced (with 'eval') gives values to following"
- echoE "\tvariables:"
- echoE "\t 'CommandLine': Command and parameters of process when launched."
- echoE "\t 'ElapsedTime': Time (in seconds) the process was running."
- echoE "\t 'ExitCode': Exit code of process."
- echoE "\t 'StandardOut': Output generated by process while running."
- echoE "\t 'StandardError': Error output generated by process while running."
- echoE "\tNote: To avoid mismatch in the number of \",',\`,ยด (which would cause"
- echoE "\t 'eval' to fail) each of them can be replaced by \\\" in 'StandardOut'"
- echoE "\t & 'StandardError' (Some commands output: \`Error message') by using"
- echoE "\t function 'CleanText' (See \$COMMON_BIN_DIR/BashCodeRepository)."
- echoE "Note: Normal usage sequence:"
- echoE "\tLaunch a process in background and get its Pid."
- echoE "\tDo other tasks."
- echoE "\tCheck if backgroung process has finished running"
- echoE "\t using '$CommandName' and Pid."
- echoE "\tRead info when backgroung process has finished."
- echoE "\tSource background process' info and use Variables' contents."
- echoE "\tIf background process has not finished in the allotted time"
- echoE "\t kill it with '$CommandName' (And get info of killed process)."
- echoE "Please read \$COMMON_BIN_DIR/BashCodeRepository for examples of usage."
- echoE
- return 0
- }
- ########### Functions. END.
- CommandOption=false;RunInBackgroundOption=false;KillProcessOption=false;ProcessFinishedOption=false
- if [ "$1" == "$CommandOptionString" ]
- then
- CommandOption=true
- shift
- else
- if [ "$1" == "$RunInBackgroundOptionString" ]
- then
- RunInBackgroundOption=true
- shift
- else
- if [ "$1" == "$KillProcessOptionString" ]
- then
- KillProcessOption=true
- shift
- else
- if [ "$1" == "$ProcessFinishedOptionString" ]
- then
- ProcessFinishedOption=true
- shift
- fi
- fi
- fi
- fi
- if [ $# -lt 1 ] || [ "$1" == "-h" ] || [ "$1" == "-?" ] || [ "$1" == "--help" ] || [ "$1" == "-help" ]
- then
- Usage
- exit 64
- fi
- if $CommandOption
- then
- if ! type "$1" &>/dev/null
- then
- echoE "$CommandName: Command '$1' not in \$PATH. Aborting!"
- exit 127
- fi
- # 'coproc': Equivalent to ending command with '&'. '&' does not work if shell invoked with `` (ProcessId=`BackgroundProcess -c Command`)
- # &>/dev/null so that no error message is given when killed. Also to allow background processes to be launched from this background process (pipes?)
- if coproc $CommandName $RunInBackgroundOptionString "$@" &>/dev/null
- then
- eval "exec ${COPROC[0]}>&-" #Close coproc stdout pipe (See Books/Science/Computer_Science/Linux/Bash_scripting/Bash_Co_Processes)
- eval "exec ${COPROC[1]}<&-" #Close coproc stdin pipe (See Books/Science/Computer_Science/Linux/Bash_scripting/Bash_Co_Processes)
- echo "$!"
- exit 0
- else
- echoE "$CommandName: Launching in background with 'coproc' failed with ExitCode: $?. Aborting!" # Should never happen but... just in case ;-)
- exit 70
- fi
- fi
- if $RunInBackgroundOption
- then
- TempFile="${TempDir}/${CommandName}_$$"
- TempErrorFile="${TempFile}.Error"
- >$TempErrorFile # So that other users can not read file
- chmod 600 $TempErrorFile # So that other users can not read file
- TempOutFile="${TempFile}.Out"
- >$TempOutFile # So that other users can not read file
- chmod 600 $TempOutFile # So that other users can not read file
- cd $TempDir # So that child process uses it as working directory (And does not tie up current wd).
- exec 0<&- # Close stdin
- exec 1>&- # Close stdout
- exec 2>&- # Close stderr
- StartTime=`date +%s` # Seconds since 1970โ01โ01
- 1>$TempOutFile 2>$TempErrorFile "$@"
- ExitCode=$?
- let ElapsedTime=`date +%s`-$StartTime
- echo -e "CommandLine=\"$@\"\n#\nElapsedTime=${ElapsedTime}\n#\nExitCode=${ExitCode}\n#\nStandardOut=\"`cat $TempOutFile`\"\n#\nStandardError=\"`cat $TempErrorFile`\"\n#" >$TempFile
- rm -f $TempErrorFile $TempOutFile
- exit 0
- fi
- if [ $# -ne 1 ]
- then
- Usage
- exit 64
- fi
- TempFile="${TempDir}/${CommandName}_$1"
- if ProcessCommandName=`2>/dev/null ps --pid=$1 h -o comm`
- then
- # If $CommandName contains $ProcessCommandName (ps returns only the 15 first characters of command).
- if [ "$CommandName" != "${CommandName/${ProcessCommandName}/}" ]
- then
- if $KillProcessOption
- then
- for Grandchild in `ps -o pid --no-headers --ppid $1`
- do
- pkill -${KillSignal} -P $Grandchild &>/dev/null # Kill BackgroundProcess' children's children (grandchildren)
- done
- pkill -${KillSignal} -P $1 &>/dev/null # -P means kill processes whose parent process ID is listed. Here: kill BackgroundProcess' children
- let "KillProcessTimeout = $KillProcessTimeout * 10" # Will be checked at 1/10 seconds
- while &>/dev/null ps --pid=$1 && [ $KillProcessTimeout -gt 0 ]
- do
- sleep 0.1
- done
- if ! &>/dev/null ps --pid=$1
- then
- if [ -f $TempFile ]
- then
- cat $TempFile
- rm -f $TempFile
- exit 0
- else
- echoE "$CommandName: Process killed but temporary file not found. No record of process '$1'."
- exit 70
- fi
- else
- echoE "$CommandName: Warning! Process '$1' could not be killed."
- exit 70
- fi
- fi
- echoE "$CommandName: Process '$1' still running."
- exit 1
- else
- echoE "$CommandName: Process '$1' running but not an instance of '$CommandName'. Aborting."
- exit 70
- fi
- fi
- if [ -f $TempFile ]
- then
- if $ProcessFinishedOption
- then
- exit 0
- fi
- if $KillProcessOption
- then
- echoE "$CommandName: Process '$1' has already exited. Kill request ignored."
- fi
- cat $TempFile
- rm -f $TempFile
- else
- echoE "$CommandName: Process not running and temporary file not found. No record of process '$1'."
- exit 70
- fi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement