Skip to content

Instantly share code, notes, and snippets.

@nkh
Last active June 14, 2023 18:15
Show Gist options
  • Save nkh/718f897cef0bacc0b75da6254456e889 to your computer and use it in GitHub Desktop.
Save nkh/718f897cef0bacc0b75da6254456e889 to your computer and use it in GitHub Desktop.
how to dynamically create a pipeline that handles options
#!/bin/bash
echo process a given input depending on options in a pipeline
echo --------------------------------------------------------------------------------
echo
inputs=("2 xxx" "1 hi" "3 abc")
# options to sort or limit the number of answers
opt_sort=1
opt_limit=2
declare -p inputs
declare -p opt_sort opt_limit
echo --------------------------------------------------------------------------------
echo solution 1: manually check the option
echo
printf '%s\n' "${inputs[@]}" |
# we can use an if
if [ "$opt_limit" -gt 0 ]; then grep -m "$opt_limit" -P '^' ; else cat; fi |
# or a more concise block
{ ((opt_sort)) && sort || cat ; } |
sed -e 's/xxx/XXX/'
echo --------------------------------------------------------------------------------
echo solution 2: use function that pipe to each other
echo
# we can declare functions which will handle the option
# the functions are chained in the call, depending on the option
# run the process and pipe to the chained commands or run the
# chained command
do_limit() { (($opt_limit)) && head -n "$opt_limit" | "$@" || "$@" ; }
do_sort() { ((opt_sort)) && sort | "$@" || { [[ -n "$@" ]] && "$@" ; } ; }
# a function with a simple operation, no option handles
do_sed() { sed -e 's/xxx/XXX/' ; }
printf '%s\n' "${inputs[@]}" | do_limit do_sort do_sed
printf '%s\n' "${inputs[@]}" | do_limit do_sort cat | do_sed
# the last option handling function needs a chained function
# this wouldn't work
# printf '%s\n' "${inputs[@]}" | do_limit do_sort
echo --------------------------------------------------------------------------------
echo solution 3: create a function that runs a list of option handling functions
echo
do_all() { do_limit do_sort do_sed ; }
printf '%s\n' "${inputs[@]}" | do_all
printf '%s\n' "${inputs[@]}" | do_all | do_sed
echo --------------------------------------------------------------------------------
echo solution 4: use list of commands, call directly
echo
# creating option handling functions with all the piping can be simplified
create() { eval "$1() { $2 | \"\$@\" || \"\$@\" ; }" ; }
# create another function that handle $opt_limit
# equivalent to do_limit() { (($opt_limit)) && head -n "$opt_limit" | "$@" || "$@" ; }
create do_limit2 '(($opt_limit)) && head -n "$opt_limit"'
# we can put all the commands in a list
commands=(do_limit2 do_sort)
# this function will al the commands in the above list
do_commands() { "${commands[@]}" cat ; }
printf '%s\n' "${inputs[@]}" | do_commands
printf '%s\n' "${inputs[@]}" | do_commands | do_sed
echo --------------------------------------------------------------------------------
echo solution 5: use list of commands, pass them as arguments
echo
# we can also define a function that accepts a list of commands to run
do_command_list() { "$@" cat ; }
# the commands are passed as arguments
printf '%s\n' "${inputs[@]}" | do_command_list "${commands[@]}"
printf '%s\n' "${inputs[@]}" | do_command_list "${commands[@]}" | do_sed
echo --------------------------------------------------------------------------------
echo solution 6: use list of commands, pass the list
echo
# we can also define a function that takes a list by name
do_command_list_by_name() { local -n array=$1 ; "${array[@]}" cat ; }
# we pass the list name
printf '%s\n' "${inputs[@]}" | do_command_list_by_name commands
printf '%s\n' "${inputs[@]}" | do_command_list_by_name commands | do_sed
echo --------------------------------------------------------------------------------
echo solution 7: use list of commands, use temporary files
echo
run_commands()
{
PIPE1=$(mktemp) PIPE2=$(mktemp)
>$PIPE1 cat
for f in "$@"
do
>$PIPE2 ; <$PIPE1 $f >$PIPE2 || <$PIPE1 cat >&$PIPE2
t=$PIPE1 PIPE1=$PIPE2 PIPE2=$t
done
<$PIPE1 cat
}
echo --------------------------------------------------------------------------------
echo solution 8: eval pipes
echo
opt_limit=2 ; run_limit() { ((opt_limit)) && head -n "$opt_limit" ; }
opt_sort=1 ; run_sort() { ((opt_sort)) && sort ; }
pipe() { p="cat $(printf "| { %s || cat ; } " "$@")" ; eval "$p" ; }
printf '%s\n' "2 xxx" "1 hi" "3 abc" | pipe run_limit run_sort
echo --------------------------------------------------------------------------------
echo solution 9: eval pipes from array
echo
pipe_list() { p="cat $(printf "| { %s || cat ; } " "${run_list[@]}")" ; eval "$p" ; }
run_list=(run_limit run_sort)
printf '%s\n' "2 xxx" "1 hi" "3 abc" | pipe_list
echo --------------------------------------------------------------------------------
echo solution 10: eval pipes from array passed as argument
echo
pipe_list_arh() { local -n list=$1 ; p="cat $(printf "| { %s || cat ; } " "${list[@]}")" ; eval "$p" ; }
printf '%s\n' "2 xxx" "1 hi" "3 abc" | pipe_list run_list
# vim: set filetype=bash :
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment