1#!/usr/bin/wish 2 3# This file provides shell command procedures cmd_fnc and t_cmd_fnc. 4 5my_source [list print.tcl] 6 7 8proc cmd_fnc { cmd_buf { quiet {} } { test_mode {} } { print_output {} }\ 9 { show_err {} } { ignore_err {} } { acceptable_shell_rcs {} } } { 10 11 # Run the given command in a shell and return the shell return code and the 12 # output as a 2 element list. 13 14 # Example usage: 15 # set result [cmd_fnc "date"]. 16 17 # Example output: 18 19 # #(CST) 2018/01/17 16:23:28.951643 - 0.001086 - Issuing: date 20 # Mon Feb 19 10:12:10 CST 2018 21 # result: 22 # result[0]: 0x00000000 23 # result[1]: Mon Feb 19 10:12:10 CST 24 # 2018 25 26 # Note: Because of the way this procedure processes parms, the user can 27 # specify blank values as a way of skipping parms. In the following 28 # example, the caller is indicating that they wish to have quiet and 29 # test_mode take their normal defaults but have print_output be 0.: 30 # cmd_fnc "date" "" "" 0 31 32 # Description of argument(s): 33 # cmd_buf The command string to be run in a shell. 34 # quiet Indicates whether this procedure should 35 # run the print_issuing() procedure which 36 # prints "Issuing: <cmd string>" to stdout. 37 # The default value is 0. 38 # test_mode If test_mode is set, this procedure will 39 # not actually run the command. If 40 # print_output is set, it will print 41 # "(test_mode) Issuing: <cmd string>" to 42 # stdout. The default value is 0. 43 # print_output If this is set, this procedure will print 44 # the stdout/stderr generated by the shell 45 # command. The default value is 1. 46 # show_err If show_err is set, this procedure will 47 # print a standardized error report if the 48 # shell command returns non-zero. The 49 # default value is 1. 50 # ignore_err If ignore_err is set, this procedure will 51 # not fail if the shell command fails. 52 # However, if ignore_err is not set, this 53 # procedure will exit 1 if the shell command 54 # fails. The default value is 1. 55 # acceptable_shell_rcs A list of acceptable shell rcs. If the 56 # shell return code is found in this list, 57 # the shell command is considered 58 # successful. The default value is {0}. 59 60 # Set defaults. 61 set_var_default quiet [get_stack_var quiet 0 2] 62 set_var_default test_mode 0 63 set_var_default print_output 1 64 set_var_default show_err 1 65 set_var_default ignore_err 1 66 set_var_default acceptable_shell_rcs 0 67 68 qpissuing $cmd_buf $test_mode 69 70 if { $test_mode } { return [list 0 ""] } 71 72 set shell_rc 0 73 74 if { [ catch {set out_buf [eval exec bash -c {$cmd_buf}]} result ] } { 75 set out_buf $result 76 set shell_rc [lindex $::errorCode 2] 77 } 78 79 if { $print_output } { puts "${out_buf}" } 80 81 # Check whether return code is acceptable. 82 if { [lsearch -exact $acceptable_shell_rcs ${shell_rc}] == -1 } { 83 # The command failed. 84 append error_message "The prior shell command failed.\n" 85 append error_message [sprint_var shell_rc "" "" 1] 86 if { $acceptable_shell_rcs != 0 } { 87 # acceptable_shell_rcs contains more than just a single element equal 88 # to 0. 89 append error_message "\n" 90 append error_message [sprint_list acceptable_shell_rcs "" "" 1] 91 } 92 if { ! $print_output } { 93 append error_message "out_buf:\n${out_buf}" 94 } 95 if { $show_err } { 96 print_error_report $error_message 97 } 98 99 if { ! $ignore_err } { 100 exit 1 101 } 102 103 } 104 105 return [list $shell_rc $out_buf] 106 107} 108 109 110proc t_cmd_fnc { args } { 111 112 # Call cmd_fnc with test_mode equal to the test_mode setting found by 113 # searching up the call stack. See cmd_fnc (above) for details for all 114 # other arguments. 115 116 # We wish to obtain a value for test_mode by searching up the call stack. 117 # This value will govern whether the command specified actually gets 118 # executed. 119 set_var_default test_mode [get_stack_var test_mode 0 2] 120 121 # Since we wish to manipulate the value of test_mode, which is the third 122 # positional parm, we must make sure we have at least 3 parms. We will now 123 # append blank values to the args list as needed to ensure that we have the 124 # minimum 3 parms. 125 set min_args 3 126 for {set ix [llength $args]} {$ix < $min_args} {incr ix} { 127 lappend args {} 128 } 129 130 # Now replace the caller's test_mode value with the value obtained from the 131 # call stack search. It does not matter what value is specified by the 132 # caller for test_mode. It will be replaced. The whole point of calling 133 # t_cmd_fnc is to allow it to set the test_mode. 134 set args [lreplace $args 2 2 $test_mode] 135 136 return [cmd_fnc {*}$args] 137 138} 139