B2_Command_Line_Tool
B2_Command_Line_Tool copied to clipboard
v1.3.6 installed via Homebrew on macOS causes Bash `_have` error
Since the PR was already closed/merged, just wanted to open an issue here as well in case nobody sees it - see https://github.com/Backblaze/B2_Command_Line_Tool/pull/497#issuecomment-415196337
To recap, v1.3.6 (specifically this commit) causes
-bash: _have: command not found
To appear on every Terminal launch.
- macOS 10.13.6
- b2-tools installed via Homebrew
Thanks. Saw it. Hoping to get to it today, though this is not my area of expertise.
We just had a change to switch from have to _have because have is deprecated. Does anybody know what the right answer is?
Not sure what the "right" answer is. Is _have a Bash4+ thing? If yes then maybe a check for ${BASH_VERSINFO[0]} before calling _have could work?
That sounds like a reasonable plan. Feel free to have a go at it, if you'd like.
So after more research, it appears that _have() is not provided by Bash 4.x, but rather by newer versions of bash_completion (which do require Bash 4.1+)
I was able to fix this without needing any changes to b2-tools by upgrading to Bash 4.4 and the newer flavor of bash-completion (appropriately named bash-completion@2).
Steps:
- Install Bash 4 and set it as your default shell
$ brew install bash
$ sudo bash -c "echo /usr/local/bin/bash >> /private/etc/shells"
$ chsh -s /usr/local/bin/bash
- Swap in new version of bash_completion
$ brew uninstall bash-completion
$ brew install bash-completion@2
- Add/update this section in your
~/.bash_profile
if [ -f /usr/local/share/bash-completion/bash_completion ]; then
source /usr/local/share/bash-completion/bash_completion
fi
- Open a new Terminal, the _have error should be gone...
_have gets called several times (I tried by adding some sort of echo logging), but only once it reports the error, so it seems that in one specific case the bash-completion environment is not properly loaded. See the end of the following snippet:
~ $ bash --login -x
[...]
+++ unset list
+++ [[ -d /usr/local/etc/bash_completion.d ]]
+++ [[ -r /usr/local/etc/bash_completion.d ]]
+++ [[ -x /usr/local/etc/bash_completion.d ]]
++++ LC_ALL=C
++++ command ls /usr/local/etc/bash_completion.d
++++ ls /usr/local/etc/bash_completion.d
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/abook
+++ [[ abook != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/abook ]]
+++ [[ -r /usr/local/etc/bash_completion.d/abook ]]
+++ . /usr/local/etc/bash_completion.d/abook
++++ have abook
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type abook
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/ant
+++ [[ ant != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/ant ]]
+++ [[ -r /usr/local/etc/bash_completion.d/ant ]]
+++ . /usr/local/etc/bash_completion.d/ant
++++ have ant
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type ant
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/apache2ctl
+++ [[ apache2ctl != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/apache2ctl ]]
+++ [[ -r /usr/local/etc/bash_completion.d/apache2ctl ]]
+++ . /usr/local/etc/bash_completion.d/apache2ctl
++++ have apache2ctl
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type apache2ctl
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/apt
+++ [[ apt != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/apt ]]
+++ [[ -r /usr/local/etc/bash_completion.d/apt ]]
+++ . /usr/local/etc/bash_completion.d/apt
++++ have apt-get
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type apt-get
++++ have apt-cache
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type apt-cache
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/apt-build
+++ [[ apt-build != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/apt-build ]]
+++ [[ -r /usr/local/etc/bash_completion.d/apt-build ]]
+++ . /usr/local/etc/bash_completion.d/apt-build
++++ have apt-build
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type apt-build
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/aptitude
+++ [[ aptitude != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/aptitude ]]
+++ [[ -r /usr/local/etc/bash_completion.d/aptitude ]]
+++ . /usr/local/etc/bash_completion.d/aptitude
++++ have aptitude
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type aptitude
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/aspell
+++ [[ aspell != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/aspell ]]
+++ [[ -r /usr/local/etc/bash_completion.d/aspell ]]
+++ . /usr/local/etc/bash_completion.d/aspell
++++ have aspell
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type aspell
++++ have=yes
++++ complete -F _aspell aspell
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/autoconf
+++ [[ autoconf != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/autoconf ]]
+++ [[ -r /usr/local/etc/bash_completion.d/autoconf ]]
+++ . /usr/local/etc/bash_completion.d/autoconf
++++ have autoconf
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type autoconf
++++ have=yes
++++ complete -F _autoconf autoconf
++++ have autoreconf
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type autoreconf
++++ have=yes
++++ complete -F _autoreconf autoreconf autoheader
++++ have autoscan
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type autoscan
++++ have=yes
++++ complete -F _autoscan autoscan autoupdate
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/automake
+++ [[ automake != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/automake ]]
+++ [[ -r /usr/local/etc/bash_completion.d/automake ]]
+++ . /usr/local/etc/bash_completion.d/automake
++++ have automake
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type automake
++++ have aclocal
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type aclocal
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/autorpm
+++ [[ autorpm != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/autorpm ]]
+++ [[ -r /usr/local/etc/bash_completion.d/autorpm ]]
+++ . /usr/local/etc/bash_completion.d/autorpm
++++ have autorpm
++++ unset -v have
++++ PATH=/usr/local/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Applications/Wireshark.app/Contents/MacOS:/Users/David/.gem/ruby/2.5.0/bin:/usr/local/sbin:/usr/local/opt/node@8/bin:/Users/David/.cargo/bin:/Users/David/Developer/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/usr/local/opt/go/libexec/bin:/Users/David/Developer/go/bin:/sbin:/usr/sbin:/usr/local/sbin
++++ type autorpm
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/b2-tools-completion.bash
+++ [[ b2-tools-completion.bash != @(*~|*.bak|*.swp|\#*\#|*.dpkg*|*.rpm@(orig|new|save)|Makefile*) ]]
+++ [[ -f /usr/local/etc/bash_completion.d/b2-tools-completion.bash ]]
+++ [[ -r /usr/local/etc/bash_completion.d/b2-tools-completion.bash ]]
+++ . /usr/local/etc/bash_completion.d/b2-tools-completion.bash
++++ _have b2
bash: _have: command not found
+++ for i in '$(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR")'
+++ i=/usr/local/etc/bash_completion.d/bash-builtins
[...]
It would be nice if it doesn't cause the error with out-of-the-box bash version on macOS.
if [ -f /usr/local/share/bash-completion/bash_completion ]; then source /usr/local/share/bash-completion/bash_completion fi
The usage of $(brew --prefix) instead of /usr/local makes it even nicer.
if [ -f $(brew --prefix)/share/bash-completion/bash_completion ]; then
source $(brew --prefix)/share/bash-completion/bash_completion
fi
@michaelnordmeyer That's true, but that adds a little bit of delay to opening new login shells. As long as you know your prefix and it stays static, it's faster to just source it directly.
This fixed it for me:
$ brew uninstall bash-completion && brew install bash-completion@2
For those who don't want to update bash and/or bash_completion, this can also be worked around by including the following in "~/.bashrc" before bash_completion is sourced:
# copied from https://github.com/scop/bash-completion/bash_completion
# to work around https://github.com/Backblaze/B2_Command_Line_Tool/issues/500
_have()
{
# Completions for system administrator commands are installed as well in
# case completion is attempted via `sudo command ...'.
PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin type $1 &>/dev/null
}
We have moved to new implementation of autocomplete a year ago installable through b2 install-autocomplete which should not have this problem.