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