Project

General

Profile

« Previous | Next » 

Revision 13212

bugfix: lib/sh/util.sh: stdout2fd(): moved after redir() which it depends on

View differences:

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