From 3188a147d88ed5f37908296e0db439444a2d74bc Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Mon, 20 Oct 2025 18:10:33 +0900 Subject: [PATCH] Use "-o fullquote" and "-o noquote" to escape Bash completions --- CHANGELOG.md | 2 ++ assets/completions/bat.bash.in | 26 ++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f388972..af748eb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ ## Other +- Use more robust approach to escaping in Bash completions, see #3448 (@akinomyoga) + ## Syntaxes ## Themes diff --git a/assets/completions/bat.bash.in b/assets/completions/bat.bash.in index 3dc56f31..66be3985 100644 --- a/assets/completions/bat.bash.in +++ b/assets/completions/bat.bash.in @@ -14,18 +14,36 @@ __bat_escape_completions() { # Do not escape if completing a quoted value. [[ $cur == [\"\']* ]] && return 0 - # printf -v to an array index is available in bash >= 4.1. - # Use it if available, as -o filenames is semantically incorrect if - # we are not actually completing filenames, and it has side effects - # (e.g. adds trailing slash to candidates matching present dirs). if (( + BASH_VERSINFO[0] > 5 || \ + BASH_VERSINFO[0] == 5 && BASH_VERSINFO[1] >= 3 + )); then + # bash >= 5.3 has "compopt -o fullquote", which exactly does + # what this function tries to do. + compopt -o fullquote + elif (( BASH_VERSINFO[0] > 4 || \ BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] > 0 )); then + # printf -v to an array index is available in bash >= 4.1. + # Use it if available, as -o filenames is semantically + # incorrect if we are not actually completing filenames, and it + # has side effects (e.g. adds trailing slash to candidates + # matching present dirs). local i for i in ${!COMPREPLY[*]}; do printf -v "COMPREPLY[i]" %q "${COMPREPLY[i]}" done + + # We can use "compopt -o noquote" available in bash >= 4.3 to + # prevent further quoting by the shell, which would be + # unexpectedly applied when a quoted result matches a filename. + if (( + BASH_VERSINFO[0] > 4 || \ + BASH_VERSINFO[0] == 4 && BASH_VERSINFO[1] >= 3 + )); then + compopt -o noquote + fi else compopt -o filenames fi