proc
This section contains functions related to handling co-processes. The Bash builtin coproc is missing features, in particular there may be only one coproc open at any time.
This library comes with L_proc_popen which allows to open any number of child processes for writing and reading.
#!/bin/bash
. $(dirname "$0")/../L_lib.sh
L_finally wait
L_finally L_kill_all_childs
childs=()
for script in 'sleep 1 && exit 1' 'sleep 2; exit 2' 'sleep 3; exit 3'; do
L_proc_popen tmp bash -c "$script"
childs+=("$tmp")
done
for i in "${childs[@]}"; do
L_proc_wait i
echo "Process [$(L_proc_get_cmd i)] pid $(L_proc_get_pid i) exited with $(L_proc_get_exitcode i)"
done
proc
¶
Processes and jobs related functions.
L_bashpid_to
¶
Get bashpid in a way compatible with Bash before 4.0.
Argument:
$1
Variable to store the result to.
L_raise
¶
Send signal to itself.
Argument:
$@
Kill arguments. See kill --help.
L_kill_all_jobs
¶
L_wait_all_jobs
¶
L_get_all_childs
¶
Get all pids of all child processes including grandchildren recursively.
Option:
-v <var>
Argument:
[$1]
Pid of the parent. Default: $BASHPID.
See: https://stackoverflow.com/a/52544126/9072753
L_get_all_childs_v
¶
L_kill_all_childs
¶
Kills all childs of the pid.
Arguments:
-
-sigspecSignal to use. -
[$1]Pid of the process to kill all childs of. Defualt: $BASHPID
L_is_fd_open
¶
Check if file descriptor is open.
Argument:
$1
file descriptor
Shellcheck disable= SC2188
L_get_free_fd_to
¶
Get free file descriptors
Argument:
$@
variables to assign with the file descriptor numbers
L_pipe
¶
Open two connected file descriptors.
This internally creates a temporary file with mkfifo The result variable is assigned an array that: - [0] element is input from the pipe, - [1] element is the output to the pipe. This is meant to mimic the pipe() C function.
Arguments:
-
<var>variable name to assign result to -
[str]template temporary filename, default: ${TMPDIR:/tmp}/L_pipe_XXXXXXXXXX
L_proc_popen
¶
Process open. Coproc replacement.
The input/output options are in three groups:
- -I and -i for stdin,
- -O and -o for stdout,
- -E and -e for stderr.
Uppercase letter option specifies the mode for the file descriptor.
There are following modes available that you can give to uppercase options -I -O and -E:
- null - redirect to or from /dev/null
- close - close the file descriptor >&-
- input - -i specifies the string to forward to stdin. Only allowed for -I.
- stdout - connect file descriptor to stdout. -o or -e value are ignored.
- stderr - connect file descriptor to stderr. -o or -e value are ignored.
- pipe - create a fifo and connect file descriptor to it. -i -o or -e option specifies part of the temporary filename.
- file - connect file descriptor to file specified by -i -o or -e option
- fd - connect file descriptor to another file descriptor specified by -i -o or -e option
There first argument specifies an output variable that will be assigned the PID.
Several global array variables hold additional information about the process:
_L_PROC_EXIT[PID]- Exitcode or empty if not yet finished._L_PROC_FD0[PID]- If -Ipipe the file descriptor connected to stdin of the program, otherwise empty._L_PROC_FD1[PID]- If -Opipe the file descriptor connected to stdout of the program, otherwise empty._L_PROC_FD2[PID]- If -Epipe the file descriptor connected to stderr of the program, otherwise empty._L_PROC_CMD[PID]- The %q escaped command that was executed.
You should use getters L_proc_get_* to extract the data from them variable.
Example
L_proc_popen -Ipipe -Opipe -Estdout proc sed 's/w/W/g'
L_proc_printf proc "%s\n" "Hello world"
L_proc_read proc line
L_proc_wait -c -v exitcode proc
echo "$line"
echo "$exitcode"
Options:
-
-I <mode>stdin mode -
-i <param>string for -Iinput, file for -Ifile, fd for -Ifd -
-O <mode>stdout mode -
-o <param>file for -Ifile, fd for -Ifd -
-E <mode>stderr mode -
-e <param>file for -Efile, fd for -Efd -
-nDryrun mode. Do not execute the generated command. Instead print it to stdout. -
-W <int>Register with L_finally a return trap on stacklevelthat will wait for the popen to finish. Typically -W 0 -
-hPrint this help and return 0.
Arguments:
-
$1variable name to store the result to. -
$@command to execute.
L_proc_get_exitcode
¶
Get exitcode of L_proc.
Option:
-v <var>
Store the output in variable instead of printing it.
Argument:
$1
PID from L_proc_popen
L_proc_get_exitcode_v
¶
L_proc_get_pid
¶
Get PID from L_proc_popen of L_proc.
Option:
-v <var>
Store the output in variable instead of printing it.
Argument:
$1
PID from L_proc_popen
L_proc_get_pid_v
¶
L_proc_get_stdin
¶
Get file descriptor for stdin of L_proc.
Option:
-v <var>
Store the output in variable instead of printing it.
Argument:
$1
PID from L_proc_popen
L_proc_get_stdin_v
¶
L_proc_get_stdout
¶
Get file descriptor for stdout of L_proc.
Option:
-v <var>
Store the output in variable instead of printing it.
Argument:
$1
PID from L_proc_popen
L_proc_get_stdout_v
¶
L_proc_get_stderr
¶
Get file descriptor for stderr of L_proc.
Option:
-v <var>
Store the output in variable instead of printing it.
Argument:
$1
PID from L_proc_popen
L_proc_get_stderr_v
¶
L_proc_get_cmd
¶
Get command of L_proc.
Option:
-v <var>
Store the output in the array variable instead of printing it.
Argument:
$1
PID from L_proc_popen
L_proc_get_cmd_v
¶
L_proc_free
¶
L_proc_popen_finally
¶
Handler that can be closed from L_finally or a signal handler.
Closes file descriptors. If L_SIGNAL is a signal, forwards it to the process. Then wait for the process termination.
Example
L_finally proc -W sleep infinity
Example
L_finally proc sleep infinity
L_finally L_proc_popen_finally "$proc"
# or
L_finally proc sleep infinity
L_finally L_eval 'L_proc_popen_finally "${!1}"' proc
Argument:
$1
L_proc value. This is because the variable may go out of scope.
This is bad. when closing a file descriptor, we "remember" that the file descriptor was closed in the variable. This is less then ideal, but I do not know at this time how to fix it better. Potentially, this can cause unrelated file descriptors to get closed. This might change in the future.
L_proc_printf
¶
Write printf formatted string to coproc.
Arguments:
-
$1PID from L_proc_popen -
$@any printf arguments
L_proc_read
¶
Exec read bultin with -u file descriptor of stdout of coproc.
Arguments:
-
$1PID from L_proc_popen -
$@any builtin read options
L_proc_read_stderr
¶
Exec read bultin with -u file descriptor of stderr of coproc.
Arguments:
-
$1PID from L_proc_popen -
$@any builtin read options
See: L_proc_read
L_proc_close
¶
Close stdin, stdout and stderr of L_proc
Argument:
$1
PID from L_proc_popen
L_proc_close_stdin
¶
Close stdin of L_proc.
Does nothing if already closed or not started with -Opipe.
Argument:
$1
PID from L_proc_popen
L_proc_close_stdout
¶
Close stdout of L_proc.
Does nothing if already closed or not started with -Opipe
Argument:
$1
PID from L_proc_popen
L_proc_close_stderr
¶
Close stderr of L_proc.
Does nothing if already closed or not started with -Epipe.
Argument:
$1
PID from L_proc_popen
L_proc_poll
¶
Check if L_proc is finished.
Argument:
$1
PID from L_proc_popen
Exit: 0 if L_proc is running, 1 otherwise
L_wait
¶
Wait for pids to be finished with a timeout and capture exit codes.
Tries to use waitpid or tail --pid or a busy loop for best performance.
The waiting is uninterruptible by signals.
Note: builtin kill with multiple pids has different exit code depending on posix mode.
Options:
-
-t <timeout>Wait for this long. Timeout 0 results in just collecting all pids. -
-v <var>Exit code of PIDs will be assigned to . The elements of -v and -p arrays are pairs. -
-p <var>PIDs that exited will be assigned to array variable . -
-l <var>Left running PIDs will be assigned to array variable . -
-P <polltime>The time to poll processes when not possible to use waitpid or tail. Default: 0.1 -
-nReturn 0 when at least one of the pids is finished. -
-bBash only. Do not use waitpid or tail. -
-hPrint this help and exit.
Argument:
$@
pids to wait on
Return:
0 on success
2 usage error 124 timeout
L_proc_wait
¶
Wait for L_proc to finish.
If L_proc has already finished execution, will only evaluate -v option.
Options:
-
-t <int>Timeout in seconds. Will try to use waitpid, tail --pid or busy loop with sleep. -
-v <var>Store the L_proc exit code in the variable. -
-cClose L_proc file descriptors before waiting. -
-hPrint this help and return 0.
Argument:
$1
PID from L_proc_popen
Exit:
0 if L_proc has finished
124 if timeout expired
L_read_fds
¶
Read from multiple file descriptors at the same time.
Note
The minimum read -t argument in Bash3.2 is 1 second. It is not possible
to set it lower or to a fraction. This does not work great for Bash3.2 for short timeout, as one read takes at least 1 second to execute.
Example
exec 10< <(for ((i=0;i<5;++i)); do echo $i; sleep 1; done)
exec 11< <(for ((i=0;i<5;++i)); do echo $i; sleep 2; done)
L_read_fds 10 a 11 b
echo "read from 10 fd text: $a"
echo "read from 11 fd text: $b"
Options:
-
-t <timeout>Timeout in seconds. -
-p <timeout>Poll timeout. The read -t argument value. Default: 0.05 or 1 in Bash3.2 -
-hPrint this help and return 0. -
-n <var>After any fd errors or becomes EOF, assign the fd number to and return 0. -
-C <callback>Each time any chunk of data is read,
evaluate the expression "
". -
-d <delim>Read -d argument. Default: '' -
-1Run the reading loop possible once.
Arguments:
-
$1File descriptor to read from. -
$2Variable to assign the output of $1. -
$@Continued pairs of file descriptor and variable names.
Return:
0 on success
124 on timeout
L_proc_communicate
¶
Communicate with L_proc.
Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.
Options:
-
-i <str>Send string to stdin.
Note that if you want to send data to the process’s stdin, you need to create the L_proc object with -I PIPE.
-
-o <var>Append stdout data to this variable. Variable is not cleared.
To get anything, you need to create L_proc object with -O PIPE.
-
-e <var>Append stderr to this variable. Variable is not cleared.
To get anything, you need to create L_proc object with -E PIPE.
-
-t <int>Timeout in seconds. -
-kKill L_proc after communication. -
-v <var>Store the output in variable instead of printing it. -
-hPrint this help and return 0.
Argument:
$1
PID from L_proc_popen
Exit: 0 on success. 2 on usage error. 124 on timeout.
L_proc_send_signal
¶
Send signal to L_proc.
Arguments:
-
$1PID from L_proc_popen -
$2signal to send
L_proc_terminate
¶
Terminate L_proc.
Argument:
$1
PID from L_proc_popen
L_proc_kill
¶
Kill L_proc.
Argument:
$1
PID from L_proc_popen