Skip to content

Commit 219ae02

Browse files
committed
Support the array PROMPT_COMMAND in Bash 5.1+
1 parent 77aec5f commit 219ae02

File tree

2 files changed

+36
-17
lines changed

2 files changed

+36
-17
lines changed

bash-preexec.sh

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,8 @@ __bp_set_ret_value() {
183183

184184
__bp_in_prompt_command() {
185185

186-
local prompt_command_array
187-
IFS=$'\n;' read -rd '' -a prompt_command_array <<< "${PROMPT_COMMAND:-}"
186+
local prompt_command_array IFS=$'\n;'
187+
read -rd '' -a prompt_command_array <<< "${PROMPT_COMMAND[*]:-}"
188188

189189
local trimmed_arg
190190
__bp_trim_whitespace trimmed_arg "${1:-}"
@@ -290,7 +290,7 @@ __bp_preexec_invoke_exec() {
290290

291291
__bp_install() {
292292
# Exit if we already have this installed.
293-
if [[ "${PROMPT_COMMAND:-}" == *"__bp_precmd_invoke_cmd"* ]]; then
293+
if [[ "${PROMPT_COMMAND[*]:-}" == *"__bp_precmd_invoke_cmd"* ]]; then
294294
return 1;
295295
fi
296296

@@ -332,11 +332,14 @@ __bp_install() {
332332

333333
# Install our hooks in PROMPT_COMMAND to allow our trap to know when we've
334334
# actually entered something.
335-
PROMPT_COMMAND=$'__bp_precmd_invoke_cmd\n'
336-
if [[ -n "$existing_prompt_command" ]]; then
337-
PROMPT_COMMAND+=${existing_prompt_command}$'\n'
338-
fi;
339-
PROMPT_COMMAND+='__bp_interactive_mode'
335+
PROMPT_COMMAND='__bp_precmd_invoke_cmd'
336+
PROMPT_COMMAND+=${existing_prompt_command:+$'\n'$existing_prompt_command}
337+
if ((BASH_VERSINFO[0] > 5 || BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 1)); then
338+
PROMPT_COMMAND+=('__bp_interactive_mode')
339+
else
340+
# shellcheck disable=SC2179 # PROMPT_COMMAND is not an array in bash <= 5.0
341+
PROMPT_COMMAND+=$'\n__bp_interactive_mode'
342+
fi
340343

341344
# Add two functions to our arrays for convenience
342345
# of definition.
@@ -359,8 +362,10 @@ __bp_install_after_session_init() {
359362
local sanitized_prompt_command
360363
__bp_sanitize_string sanitized_prompt_command "${PROMPT_COMMAND:-}"
361364
if [[ -n "$sanitized_prompt_command" ]]; then
365+
# shellcheck disable=SC2178 # PROMPT_COMMAND is not an array in bash <= 5.0
362366
PROMPT_COMMAND=${sanitized_prompt_command}$'\n'
363367
fi;
368+
# shellcheck disable=SC2179 # PROMPT_COMMAND is not an array in bash <= 5.0
364369
PROMPT_COMMAND+=${__bp_install_string}
365370
}
366371

test/bash-preexec.bats

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,23 @@ setup() {
88
source "${BATS_TEST_DIRNAME}/../bash-preexec.sh"
99
}
1010

11+
# Evaluates all the elements of PROMPT_COMMAND
12+
eval_PROMPT_COMMAND() {
13+
local prompt_command
14+
for prompt_command in "${PROMPT_COMMAND[@]}"; do
15+
eval "$prompt_command"
16+
done
17+
}
18+
19+
# Joins the elements of PROMPT_COMMAND with $'\n'
20+
join_PROMPT_COMMAND() {
21+
local IFS=$'\n'
22+
echo "${PROMPT_COMMAND[*]}"
23+
}
24+
1125
bp_install() {
1226
__bp_install_after_session_init
13-
eval "$PROMPT_COMMAND"
27+
eval_PROMPT_COMMAND
1428
}
1529

1630
test_echo() {
@@ -63,7 +77,7 @@ set_exit_code_and_run_precmd() {
6377
[[ "$PROMPT_COMMAND" == *"trap - DEBUG"* ]] || return 1
6478
[[ "$PROMPT_COMMAND" == *"__bp_install"* ]] || return 1
6579

66-
eval "$PROMPT_COMMAND"
80+
eval_PROMPT_COMMAND
6781

6882
[[ "$PROMPT_COMMAND" != *"trap DEBUG"* ]] || return 1
6983
[[ "$PROMPT_COMMAND" != *"__bp_install"* ]] || return 1
@@ -106,7 +120,7 @@ set_exit_code_and_run_precmd() {
106120
bp_install
107121

108122
PROMPT_COMMAND="$PROMPT_COMMAND; true"
109-
eval "$PROMPT_COMMAND"
123+
eval_PROMPT_COMMAND
110124
}
111125

112126
@test "Appending or prepending to PROMPT_COMMAND should work after bp_install_after_session_init" {
@@ -119,7 +133,7 @@ set_exit_code_and_run_precmd() {
119133
PROMPT_COMMAND="true; $PROMPT_COMMAND"
120134
PROMPT_COMMAND="true; $PROMPT_COMMAND"
121135
PROMPT_COMMAND="true $nl $PROMPT_COMMAND"
122-
eval "$PROMPT_COMMAND"
136+
eval_PROMPT_COMMAND
123137
}
124138

125139
# Case where a user is appending or prepending to PROMPT_COMMAND.
@@ -132,21 +146,21 @@ set_exit_code_and_run_precmd() {
132146
PROMPT_COMMAND="$PROMPT_COMMAND"$'\n echo after'
133147
PROMPT_COMMAND="echo after2; $PROMPT_COMMAND;"
134148

135-
eval "$PROMPT_COMMAND"
149+
eval_PROMPT_COMMAND
136150

137151
expected_result=$'__bp_precmd_invoke_cmd\necho after2; echo before; echo before2\n echo after\n__bp_interactive_mode'
138-
[ "$PROMPT_COMMAND" == "$expected_result" ]
152+
[ "$(join_PROMPT_COMMAND)" == "$expected_result" ]
139153
}
140154

141155
@test "Adding to PROMPT_COMMAND after with semicolon" {
142156
PROMPT_COMMAND="echo before"
143157
__bp_install_after_session_init
144158
PROMPT_COMMAND="$PROMPT_COMMAND; echo after"
145159

146-
eval "$PROMPT_COMMAND"
160+
eval_PROMPT_COMMAND
147161

148162
expected_result=$'__bp_precmd_invoke_cmd\necho before\n echo after\n__bp_interactive_mode'
149-
[ "$PROMPT_COMMAND" == "$expected_result" ]
163+
[ "$(join_PROMPT_COMMAND)" == "$expected_result" ]
150164
}
151165

152166
@test "during install PROMPT_COMMAND and precmd functions should be executed each once" {
@@ -157,7 +171,7 @@ set_exit_code_and_run_precmd() {
157171
PROMPT_COMMAND="echo after2; $PROMPT_COMMAND;"
158172

159173
precmd() { echo "inside precmd"; }
160-
run eval "$PROMPT_COMMAND"
174+
run eval_PROMPT_COMMAND
161175
[ "${lines[0]}" == "after2" ]
162176
[ "${lines[1]}" == "before" ]
163177
[ "${lines[2]}" == "before2" ]

0 commit comments

Comments
 (0)