|
1 | 1 | #!/usr/bin/env bash |
2 | 2 | # shellcheck disable=SC2154 # pipestatus is zsh-specific, set by the shell |
3 | 3 | # shellcheck disable=SC2034 # Test function variables used for validation patterns |
| 4 | +set -uo pipefail |
| 5 | +IFS=$'\n\t' |
4 | 6 | # ============================================================================= |
5 | 7 | # NAME : combined.history.sh |
6 | 8 | # DESCRIPTION : Logs commands in Bash and Zsh interactive shells. |
|
111 | 113 | # ============================================================================= |
112 | 114 | # Fallback logging if logger not provided |
113 | 115 | # ============================================================================= |
114 | | -if ! declare -f info > /dev/null; then function info() { printf '[* INFO ] %s\n' "${1}"; }; fi |
115 | | -if ! declare -f warn > /dev/null; then function warn() { printf '[! WARN ] %s\n' "${1}" >&2; }; fi |
| 116 | +if ! declare -f info > /dev/null; then function info() { printf '[* INFO ] %s\n' "${1}"; }; fi |
| 117 | +if ! declare -f warn > /dev/null; then function warn() { printf '[! WARN ] %s\n' "${1}" >&2; }; fi |
116 | 118 | if ! declare -f error > /dev/null; then function error() { printf '[- ERROR ] %s\n' "${1}" >&2; }; fi |
117 | | -if ! declare -f pass > /dev/null; then function pass() { printf '[+ PASS ] %s\n' "${1}"; }; fi |
118 | | -if ! declare -f fail > /dev/null; then function fail() { printf '[! FAIL ] %s\n' "${1}" >&2; }; fi |
| 119 | +if ! declare -f pass > /dev/null; then function pass() { printf '[+ PASS ] %s\n' "${1}"; }; fi |
| 120 | +if ! declare -f fail > /dev/null; then function fail() { printf '[! FAIL ] %s\n' "${1}" >&2; }; fi |
119 | 121 | if ! declare -f debug > /dev/null; then function debug() { printf '[# DEBUG ] %s\n' "${1}"; }; fi |
120 | 122 |
|
121 | 123 | # ============================================================================= |
@@ -483,13 +485,13 @@ EOF |
483 | 485 | bash) |
484 | 486 | # Use parameter expansion instead of sed for better performance |
485 | 487 | command="$(history 1)" |
486 | | - command="${command#"${command%%[![:space:]]*}"}" # ltrim |
487 | | - command="${command#*[0-9] }" # Remove leading number |
488 | | - command="${command#*] }" # Remove timestamp if present |
| 488 | + command="${command#"${command%%[![:space:]]*}"}" # ltrim |
| 489 | + command="${command#*[0-9] }" # Remove leading number |
| 490 | + command="${command#*] }" # Remove timestamp if present |
489 | 491 | ;; |
490 | 492 | zsh) |
491 | 493 | command="$(fc -ln -1)" |
492 | | - command="${command#"${command%%[![:space:]]*}"}" # ltrim |
| 494 | + command="${command#"${command%%[![:space:]]*}"}" # ltrim |
493 | 495 | ;; |
494 | 496 | *) |
495 | 497 | command="" |
@@ -537,13 +539,13 @@ EOF |
537 | 539 |
|
538 | 540 | # Escape dangerous characters to prevent command injection |
539 | 541 | # Using tr to remove control chars, then parameter expansion for safety |
540 | | - local cleaned="${raw//\\/\\\\}" # escape backslashes |
541 | | - cleaned="${cleaned//\"/\\\"}" # escape double quotes |
542 | | - cleaned="${cleaned//\'/\\\'}" # escape single quotes |
543 | | - cleaned="${cleaned//${bt}/\\${bt}}" # escape backticks (using hex var) |
544 | | - cleaned="${cleaned//\$/\\\$}" # escape $ to prevent expansion |
545 | | - cleaned="${cleaned//\(/\\\(}" # escape opening parenthesis |
546 | | - cleaned="${cleaned//\)/\\\)}" # escape closing parenthesis |
| 542 | + local cleaned="${raw//\\/\\\\}" # escape backslashes |
| 543 | + cleaned="${cleaned//\"/\\\"}" # escape double quotes |
| 544 | + cleaned="${cleaned//\'/\\\'}" # escape single quotes |
| 545 | + cleaned="${cleaned//${bt}/\\${bt}}" # escape backticks (using hex var) |
| 546 | + cleaned="${cleaned//\$/\\\$}" # escape $ to prevent expansion |
| 547 | + cleaned="${cleaned//\(/\\\(}" # escape opening parenthesis |
| 548 | + cleaned="${cleaned//\)/\\\)}" # escape closing parenthesis |
547 | 549 |
|
548 | 550 | # Strip control characters |
549 | 551 | cleaned="$(printf '%s' "${cleaned}" | tr -d '[:cntrl:]')" |
@@ -633,21 +635,16 @@ EOF |
633 | 635 | write_log_entry "${log_line}" |
634 | 636 | } |
635 | 637 |
|
636 | | - # ============================================================================= |
| 638 | + ############################################################################### |
637 | 639 | # trace_run |
638 | | - #============================== |
639 | | - # Runs a script under tracing (set -x), logging each executed command |
640 | | - # to the main log and an optional per-run trace log. |
641 | | - # |
642 | | - # Usage: |
643 | | - # trace_run <script_path> [args...] |
644 | | - # |
645 | | - # Return Values: |
646 | | - # 0 = success |
647 | | - # 1 = invalid arguments |
648 | | - # 2 = script not executable |
649 | | - # 3 = failed permissions on log file |
650 | | - # ============================================================================= |
| 640 | + #------------------------------------------------------------------------------ |
| 641 | + # Purpose : Run a script under tracing (set -x), logging each command |
| 642 | + # Usage : trace_run <script_path> [args...] |
| 643 | + # Arguments: |
| 644 | + # $1 : script_path - Path to script to trace |
| 645 | + # $@ : args - Optional arguments to pass to script |
| 646 | + # Returns : 0 success, 1 invalid args, 2 not executable, 3 log permissions |
| 647 | + ############################################################################### |
651 | 648 | function trace_run() { |
652 | 649 | local target_script shell_type timestamp per_run_log session_info rc |
653 | 650 | local interpreter first_line |
@@ -758,16 +755,13 @@ EOF |
758 | 755 | return "${rc}" |
759 | 756 | } |
760 | 757 |
|
761 | | - # ============================================================================= |
| 758 | + ############################################################################### |
762 | 759 | # test_logging_setup |
763 | | - # ------------------ |
764 | | - # Test mode to validate that: |
765 | | - # - log file is writable |
766 | | - # - flock is available |
767 | | - # - syslog is working (if enabled) |
768 | | - # - logrotate config exists (if enabled) |
769 | | - # - log entries can be written |
770 | | - # ============================================================================= |
| 760 | + #------------------------------------------------------------------------------ |
| 761 | + # Purpose : Validate logging setup (file, flock, syslog, logrotate) |
| 762 | + # Usage : test_logging_setup |
| 763 | + # Returns : 0 if all tests pass, 1 on failure |
| 764 | + ############################################################################### |
771 | 765 | function test_logging_setup() { |
772 | 766 | local test_message logrotate_file test_line test_random |
773 | 767 |
|
|
0 commit comments