Always use indirection to locate interpreter
When I first installed xbar, I downloaded a whole load of different plugins and realised almost none of them are working correctly, i.e. many bash script features such as command substitutions were not working.
I made a plugin named 001-test1.1s.bash which is simply:
#!/bin/bash
echo $BASH_VERSION
Running this script in terminal with $ bash 001-test1.1s.bash gives an output of 5.1.8(1)-release, which is what I would expect the output to be when running with xbar. However xbar outputs 3.2.57(1)-release, a very old version of bash.
After further research, I found that /bin/sh in macOS is just an old version of /bin/bash running in sh compatibility mode, and if I run the script with sh in terminal i.e. $ sh 001-test1.1s.bash this gives exactly the same output, so I am guessing that xbar is running the script with /bin/sh, and not respecting the shebang at the top of the file or the .bash file extension.
Hey @ryan-mooore thanks for opening this. xbar executes it like a normal program so I wonder if it's something to do with the .bash extension? Can you try .sh and see if that helps?
Yep, this still occurs with .sh extensions - this is how I first notice the issue because I couldn't use any shell script plugins. changing the extension to .bash was just an attempt to fix this behaviour.
For more info I am on an M1 MacBook Air running MacOS 12 beta 6. I am using the latest beta of xbar with M1 support.
My default shell is fish but changing back to zsh did not fix the problem.
Just worked out that this is because /bin/bash refers to the old 3.x bash on my machine. If I try and run any bash script with a #!/bin/bash shebang it tries to execute it with bash 3 and breaks. If I set the shebang on any bash script to #!/opt/homebrew/bin/bash (output of which bash) or #!/usr/bin/env bash then it works fine.
This is more a problem with lack of guidelines around xbar-plugins than anything else. All plugins should be using the !#/usr/bin/env XXX shebang which searches the user's $PATH for the binary. A lot of plugins already seem to be doing this but there are many more that aren't. I suppose this is especially relevant for macOS because binaries can be installed in a lot of different places.
Great feedback! We'll update the docs.
I've added this PR: https://github.com/matryer/xbar/pull/766 - do you think that covers it?
Perfect, now I guess the only issue is people trying to run already existing plugins like I tried to, I guess you don't want to go around changing other people's plugins?
My first experience with xbar was downloading a few plugins and half of them being broken, which is not a great user experience. Any plugin that started with a !#/bin/bash shebang and had string command substitution (i.e. echo "$(pwd)" was broken, such as the yabai_skhd or xkcd plugins. After more testing most plugins still work with the old bash for me, but for people that don't have any version of bash installed at /bin/bash even more of the existing plugins would be broken.
One solution, and I'm not saying this is a good idea, is to rewrite the shebang line for the script on import...
That's definitely a potential solution..
Here's the issue as I see it: the file loader needs to know what interpreter to use to run the script. This is essentially just a piece of metadata of the script. Convieniently there's an already widely established convention for that metadata with the shebang. However it has always had the core problem of bad portability, which is very important for this app. So the solutions I can see are:
- Just update all the old plugins to the
usr/bin/envstyle shebang and only accept new plugins that use this - Try and parse the shebang and always evaluate it as
usr/bin/enveven when the user has hardcoded an interpreter path. Could potentially cause confusion - Ignore the shebang altogether and rely on a more controlled form of metadata, like a new
<xbar.interpreter>tag or something similar, so choosing the interpreter can be detached from dodgy shebang lines