From 73f523e4ee542d3efa788bf61237842205851ca0 Mon Sep 17 00:00:00 2001 From: Stephane Chazelas Date: Sun, 24 Aug 2025 09:12:18 +0100 Subject: [PATCH] fix bash completion when the user has changed $IFS Like in the Korn shell, "${COMP_WORDS[*]}" in bash joins the elements of the array with the first character of $IFS, and $(...) and $1 unquoted cause their expansion to be split on characters of $IFS (and be subjected to globbing). Here, we want the COMP_WORDS elements to be joined with space characters and $(...) to be split on space (and possibly tab and newline in the future) like with the default value of $IFS (or when $IFS is unset). So we set IFS locally to space+tab+newline (better than "local IFS" alone which would only make IFS unset in the function if the localvar_inherit option was not enabled (bash has no equivalent of zsh's "emulate -L zsh" to have default option settings locally in a function)). Globbing is still performed on the resulting words (unless the user enabled the noglob option), which is still a problem for instance when we offer file or directory completions when files/directories paths contain wildcard characters, but then again at the moment any character special in the syntax of the shell (including wildcards, space, ;|()<> etc) are a problem anyway as we don't quote them like bash's default file completion does, so it's probably not worth fixing until that other issue is addressed. At the moment pip's file completion only works properly on very tame file names. The ash-style "local -; set -o noglob" which would be the obvious fix for that wouldn't work with the ancient version of bash found on macos. --- news/13555.bugfix.rst | 1 + src/pip/_internal/commands/completion.py | 3 ++- tests/functional/test_completion.py | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 news/13555.bugfix.rst diff --git a/news/13555.bugfix.rst b/news/13555.bugfix.rst new file mode 100644 index 00000000000..d0694f610c1 --- /dev/null +++ b/news/13555.bugfix.rst @@ -0,0 +1 @@ +Fix bash completion when the ``$IFS`` variable has been modified from its default. diff --git a/src/pip/_internal/commands/completion.py b/src/pip/_internal/commands/completion.py index 6d9597bdea0..7ba205d7263 100644 --- a/src/pip/_internal/commands/completion.py +++ b/src/pip/_internal/commands/completion.py @@ -14,9 +14,10 @@ "bash": """ _pip_completion() {{ + local IFS=$' \\t\\n' COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\ COMP_CWORD=$COMP_CWORD \\ - PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) + PIP_AUTO_COMPLETE=1 "$1" 2>/dev/null ) ) }} complete -o default -F _pip_completion {prog} """, diff --git a/tests/functional/test_completion.py b/tests/functional/test_completion.py index f0396aa0c68..01a8d819c58 100644 --- a/tests/functional/test_completion.py +++ b/tests/functional/test_completion.py @@ -15,9 +15,10 @@ """\ _pip_completion() { + local IFS=$' \\t\\n' COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\ COMP_CWORD=$COMP_CWORD \\ - PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) + PIP_AUTO_COMPLETE=1 "$1" 2>/dev/null ) ) } complete -o default -F _pip_completion pip""", ),