Revision 13212
Added by Aaron Marcuse-Kubitza over 10 years ago
trunk/lib/sh/util.sh | ||
---|---|---|
795 | 795 |
if self_being_included; then |
796 | 796 |
|
797 | 797 |
|
798 |
#### streams
|
|
798 |
#### fds
|
|
799 | 799 |
|
800 | 800 |
fd_exists() { (: <&"$1") 2>/dev/null; } |
801 | 801 |
|
... | ... | |
836 | 836 |
set_fds "$1" |
837 | 837 |
} |
838 | 838 |
|
839 |
stdout2fd() # usage: fd=# stdout2fd cmd... |
|
840 |
{ |
|
841 |
echo_func; kw_params fd; : "${fd?}" |
|
842 |
if test "$fd" != 1; then local redirs=(">&$fd" "${redirs[@]}"); fi |
|
843 |
redir "$@" |
|
844 |
} |
|
845 |
|
|
846 |
function filter_fd() # usage: (fd=# [redirs=] filter_fd filter_cmd...; \ |
|
847 |
# with filter...) # be sure ${redirs[@]} is not set to an outer value |
|
848 |
# useful e.g. to filter logging output or highlight errors |
|
849 |
{ |
|
850 |
echo_func; kw_params fd; : "${fd?}" |
|
851 |
set_fds "$fd>" >(pipe_delay; stdout2fd "$@") |
|
852 |
pipe_delay; pipe_delay # wait for >()'s pipe_delay and initial logging |
|
853 |
} |
|
854 |
alias filter_fd='"filter_fd" ' # last space alias-expands next word |
|
855 |
|
|
856 |
stderr2stdout() # usage: { stderr2stdout cmd...|use stderr...; } 41>&1 |
|
857 |
# **IMPORTANT**: fd 41 must later be redirected back to fd 1 |
|
858 |
# unlike `2>&1`, logs stderr |
|
859 |
# redirects the command stdout to fd 41 to avoid collision with stderr |
|
860 |
{ |
|
861 |
echo_func |
|
862 |
# command causes log_fd to be re-filtered, so that stderr is also filtered. |
|
863 |
# fd 2 is *not* redirected back to fd 2, to allow log-filtering out an |
|
864 |
# otherwise-confusing benign error. |
|
865 |
"$@" 2> >(log++ command tee /dev/fd/"$log_fd") >&41 #redirects 2->{1,log_fd} |
|
866 |
} |
|
867 |
|
|
868 |
stdout_contains() |
|
869 |
# usage: { stderr2stdout cmd|stdout_contains echo_run grep ...; } 41>&1 |
|
870 |
{ |
|
871 |
log_local; log++; echo_func |
|
872 |
pipe_delay; pipe_delay; pipe_delay; "$@"|echo_stdout >/dev/null |
|
873 |
} |
|
874 |
|
|
875 |
stderr_matches() # usage: pattern=... [ignore_e=#] stderr_matches cmd... |
|
876 |
{ |
|
877 |
echo_func; kw_params pattern ignore_e; : "${pattern?}" |
|
878 |
if test "$ignore_e"; then local benign_error=1; fi |
|
879 |
|
|
880 |
# not necessary to allow callers to handle the error themselves (which would |
|
881 |
# require *every* caller to wrap this function in prep_try/rethrow), because |
|
882 |
# they would just handle it by errexiting anyways |
|
883 |
prep_try |
|
884 |
|
|
885 |
set +o errexit # avoid errexiting since @PIPESTATUS will be used instead |
|
886 |
{ stderr2stdout "$@"|stdout_contains echo_run grep -E "$pattern"; } 41>&1 |
|
887 |
local PIPESTATUS_=("${PIPESTATUS[@]}") # save b/c it's reset after each cmd |
|
888 |
set -o errexit |
|
889 |
|
|
890 |
# handle any error |
|
891 |
e="${PIPESTATUS_[0]}" # 1st command's exit status -> $e |
|
892 |
local matches="$(errexit "${PIPESTATUS_[1]}"; exit2bool)" |
|
893 |
if test "$matches"; then ignore_e "$ignore_e"; fi #also works w/ ignore_e='' |
|
894 |
rethrow_exit #force-exit b/c caller's test of return status disables errexit |
|
895 |
|
|
896 |
return "${PIPESTATUS_[1]}" # 2nd command's exit status -> $? |
|
897 |
} |
|
898 |
|
|
899 |
fi # load new aliases |
|
900 |
if self_being_included; then |
|
901 |
|
|
902 |
function ignore_err_msg() # usage: pattern=... [ignore_e=#] ignore_err_msg cmd |
|
903 |
# unlike `|| true`, this suppresses only errors caused by a particular error |
|
904 |
# *message*, rather than all error exit statuses |
|
905 |
{ |
|
906 |
echo_func; kw_params pattern; : "${pattern?}" |
|
907 |
stderr_matches "$@" || true # also ignore false exit status on no match |
|
908 |
} |
|
909 |
alias ignore_err_msg='"ignore_err_msg" ' # last space alias-expands next word |
|
910 |
|
|
911 | 839 |
# convention: use fd 40/41/42 for command-specific alternate stdin/stdout/stderr |
912 | 840 |
# mnemonic: 4 looks like A for Alternate |
913 | 841 |
# do NOT use 1x, which are used by eval (which is used by set_fds()) |
... | ... | |
1114 | 1042 |
|
1115 | 1043 |
echo_stdout() { echo_stdin; } # usage: cmd|echo_stdout |
1116 | 1044 |
|
1045 |
stdout2fd() # usage: fd=# stdout2fd cmd... |
|
1046 |
{ |
|
1047 |
echo_func; kw_params fd; : "${fd?}" |
|
1048 |
if test "$fd" != 1; then local redirs=(">&$fd" "${redirs[@]}"); fi |
|
1049 |
redir "$@" |
|
1050 |
} |
|
1117 | 1051 |
|
1052 |
function filter_fd() # usage: (fd=# [redirs=] filter_fd filter_cmd...; \ |
|
1053 |
# with filter...) # be sure ${redirs[@]} is not set to an outer value |
|
1054 |
# useful e.g. to filter logging output or highlight errors |
|
1055 |
{ |
|
1056 |
echo_func; kw_params fd; : "${fd?}" |
|
1057 |
set_fds "$fd>" >(pipe_delay; stdout2fd "$@") |
|
1058 |
pipe_delay; pipe_delay # wait for >()'s pipe_delay and initial logging |
|
1059 |
} |
|
1060 |
alias filter_fd='"filter_fd" ' # last space alias-expands next word |
|
1061 |
|
|
1062 |
stderr2stdout() # usage: { stderr2stdout cmd...|use stderr...; } 41>&1 |
|
1063 |
# **IMPORTANT**: fd 41 must later be redirected back to fd 1 |
|
1064 |
# unlike `2>&1`, logs stderr |
|
1065 |
# redirects the command stdout to fd 41 to avoid collision with stderr |
|
1066 |
{ |
|
1067 |
echo_func |
|
1068 |
# command causes log_fd to be re-filtered, so that stderr is also filtered. |
|
1069 |
# fd 2 is *not* redirected back to fd 2, to allow log-filtering out an |
|
1070 |
# otherwise-confusing benign error. |
|
1071 |
"$@" 2> >(log++ command tee /dev/fd/"$log_fd") >&41 #redirects 2->{1,log_fd} |
|
1072 |
} |
|
1073 |
|
|
1074 |
stdout_contains() |
|
1075 |
# usage: { stderr2stdout cmd|stdout_contains echo_run grep ...; } 41>&1 |
|
1076 |
{ |
|
1077 |
log_local; log++; echo_func |
|
1078 |
pipe_delay; pipe_delay; pipe_delay; "$@"|echo_stdout >/dev/null |
|
1079 |
} |
|
1080 |
|
|
1081 |
stderr_matches() # usage: pattern=... [ignore_e=#] stderr_matches cmd... |
|
1082 |
{ |
|
1083 |
echo_func; kw_params pattern ignore_e; : "${pattern?}" |
|
1084 |
if test "$ignore_e"; then local benign_error=1; fi |
|
1085 |
|
|
1086 |
# not necessary to allow callers to handle the error themselves (which would |
|
1087 |
# require *every* caller to wrap this function in prep_try/rethrow), because |
|
1088 |
# they would just handle it by errexiting anyways |
|
1089 |
prep_try |
|
1090 |
|
|
1091 |
set +o errexit # avoid errexiting since @PIPESTATUS will be used instead |
|
1092 |
{ stderr2stdout "$@"|stdout_contains echo_run grep -E "$pattern"; } 41>&1 |
|
1093 |
local PIPESTATUS_=("${PIPESTATUS[@]}") # save b/c it's reset after each cmd |
|
1094 |
set -o errexit |
|
1095 |
|
|
1096 |
# handle any error |
|
1097 |
e="${PIPESTATUS_[0]}" # 1st command's exit status -> $e |
|
1098 |
local matches="$(errexit "${PIPESTATUS_[1]}"; exit2bool)" |
|
1099 |
if test "$matches"; then ignore_e "$ignore_e"; fi #also works w/ ignore_e='' |
|
1100 |
rethrow_exit #force-exit b/c caller's test of return status disables errexit |
|
1101 |
|
|
1102 |
return "${PIPESTATUS_[1]}" # 2nd command's exit status -> $? |
|
1103 |
} |
|
1104 |
|
|
1105 |
fi # load new aliases |
|
1106 |
if self_being_included; then |
|
1107 |
|
|
1108 |
function ignore_err_msg() # usage: pattern=... [ignore_e=#] ignore_err_msg cmd |
|
1109 |
# unlike `|| true`, this suppresses only errors caused by a particular error |
|
1110 |
# *message*, rather than all error exit statuses |
|
1111 |
{ |
|
1112 |
echo_func; kw_params pattern; : "${pattern?}" |
|
1113 |
stderr_matches "$@" || true # also ignore false exit status on no match |
|
1114 |
} |
|
1115 |
alias ignore_err_msg='"ignore_err_msg" ' # last space alias-expands next word |
|
1116 |
|
|
1117 |
|
|
1118 | 1118 |
#### commands |
1119 | 1119 |
|
1120 | 1120 |
already_exists_msg() # usage: cond || what=... already_exists_msg || return 0 |
Also available in: Unified diff
bugfix: lib/sh/util.sh: stdout2fd(): moved after redir() which it depends on