2020
2121set -euo pipefail
2222
23- # Parse arguments
2423MODE=" check"
25- if [ $# -gt 0 ]; then
24+ FILE_MODE=" all"
25+ FILES=()
26+
27+ # Accept mode flags plus optional file paths. In pre-commit, matching staged
28+ # shell files are passed as positional arguments.
29+ while [[ $# -gt 0 ]]; do
2630 case " $1 " in
2731 --check)
2832 MODE=" check"
33+ shift
2934 ;;
3035 --fix)
3136 MODE=" fix"
37+ shift
3238 ;;
33- * )
34- echo " Usage: $0 [--check|--fix]"
35- echo " --check Check shell scripts for issues (default)"
36- echo " --fix Show detailed suggestions for fixes"
39+ --staged)
40+ FILE_MODE=" staged"
41+ shift
42+ ;;
43+ --all)
44+ FILE_MODE=" all"
45+ shift
46+ ;;
47+ --help|-h)
48+ echo " Usage: $0 [--check|--fix] [--staged|--all] [files...]"
49+ echo " --check Check shell scripts for issues (default)"
50+ echo " --fix Show detailed suggestions for fixes"
51+ echo " --staged Check staged shell scripts"
52+ echo " --all Check all shell scripts (default)"
53+ exit 0
54+ ;;
55+ -* )
56+ echo " Unknown option: $1 "
57+ echo " Use --help for usage information"
3758 exit 1
3859 ;;
60+ * )
61+ FILES+=(" $1 " )
62+ shift
63+ ;;
3964 esac
40- fi
41-
42- # Check if shellcheck is installed
43- if ! command -v shellcheck & > /dev/null; then
44- echo " ❌ shellcheck command not found"
45- echo " 💡 Install it using:"
46- echo " • Ubuntu/Debian: sudo apt-get install shellcheck"
47- echo " • macOS: brew install shellcheck"
48- echo " • Or visit: https://www.shellcheck.net/"
49- exit 1
50- fi
51-
52- echo " shellcheck version: $( shellcheck --version) "
65+ done
5366
5467# Get repository root
5568REPO_ROOT=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) /../.." && pwd) "
@@ -75,22 +88,66 @@ for path in "${EXCLUDE_PATHS[@]}"; do
7588 FIND_EXCLUDE_ARGS+=(" -not" " -path" " $path " )
7689done
7790
91+ # Keep --staged for manual runs; pre-commit normally passes matching staged
92+ # files directly through pass_filenames.
93+ if [ ${# FILES[@]} -eq 0 ] && [ " $FILE_MODE " = " staged" ]; then
94+ while IFS= read -r script; do
95+ if [ ! -f " $script " ]; then
96+ continue
97+ fi
98+
99+ # Match normal .sh files and executable scripts with shell shebangs.
100+ if [[ " $script " == * .sh ]] || head -n 1 " $script " | grep -qE ' ^#!.*[^[:alnum:]_](bash|dash|ksh|zsh|sh)([[:space:]]|$)' ; then
101+ FILES+=(" $script " )
102+ fi
103+ done < <( git diff --cached --name-only --diff-filter=ACM)
104+
105+ if [ ${# FILES[@]} -eq 0 ]; then
106+ echo " ✅ No staged shell scripts to check"
107+ exit 0
108+ fi
109+ fi
110+
111+ # Check if shellcheck is installed
112+ if ! command -v shellcheck & > /dev/null; then
113+ echo " ❌ shellcheck command not found"
114+ echo " 💡 Install it using:"
115+ echo " • Ubuntu/Debian: sudo apt-get install shellcheck"
116+ echo " • macOS: brew install shellcheck"
117+ echo " • Or visit: https://www.shellcheck.net/"
118+ exit 1
119+ fi
120+
121+ echo " shellcheck version: $( shellcheck --version) "
122+
78123if [ " $MODE " = " fix" ]; then
79124 echo " 🔧 Running shellcheck with detailed suggestions..."
80125 echo " "
81126 echo " Note: shellcheck does not support automatic fixing."
82127 echo " Please review the suggestions below and fix issues manually."
83128 echo " "
84129
85- # Run with detailed format
86130 FAILED=0
87- while IFS= read -r -d ' ' script; do
88- echo " Checking: $script "
89- if ! shellcheck -x -f gcc " $script " ; then
90- FAILED=1
91- fi
92- echo " "
93- done < <( find . -type f -name " *.sh" " ${FIND_EXCLUDE_ARGS[@]} " -print0)
131+ # Use staged or explicitly provided files when present; otherwise keep the
132+ # historical full-repository behavior for CI/manual all-file checks.
133+ if [ ${# FILES[@]} -gt 0 ]; then
134+ for script in " ${FILES[@]} " ; do
135+ [ -f " $script " ] || continue
136+ echo " Checking: $script "
137+ if ! shellcheck -x -f gcc " $script " ; then
138+ FAILED=1
139+ fi
140+ echo " "
141+ done
142+ else
143+ while IFS= read -r -d ' ' script; do
144+ echo " Checking: $script "
145+ if ! shellcheck -x -f gcc " $script " ; then
146+ FAILED=1
147+ fi
148+ echo " "
149+ done < <( find . -type f -name " *.sh" " ${FIND_EXCLUDE_ARGS[@]} " -print0)
150+ fi
94151
95152 if [ $FAILED -eq 1 ]; then
96153 echo " ❌ Found issues in shell scripts"
@@ -102,8 +159,18 @@ if [ "$MODE" = "fix" ]; then
102159else
103160 echo " 🔍 Checking shell scripts..."
104161
105- # Run shellcheck on all shell scripts (checks all severities: error, warning, info, style)
106- if find . -type f -name " *.sh" " ${FIND_EXCLUDE_ARGS[@]} " -exec shellcheck -x {} +; then
162+ # Use staged or explicitly provided files when present; otherwise keep the
163+ # historical full-repository behavior for CI/manual all-file checks.
164+ if [ ${# FILES[@]} -gt 0 ]; then
165+ if shellcheck -x " ${FILES[@]} " ; then
166+ echo " ✅ All shell scripts passed shellcheck"
167+ else
168+ echo " "
169+ echo " ❌ Shellcheck found issues in shell scripts"
170+ echo " 💡 Run '$0 --fix' to see detailed suggestions"
171+ exit 1
172+ fi
173+ elif find . -type f -name " *.sh" " ${FIND_EXCLUDE_ARGS[@]} " -exec shellcheck -x {} +; then
107174 echo " ✅ All shell scripts passed shellcheck"
108175 else
109176 echo " "
0 commit comments