Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple shell commands in bash= call fail #786

Open
HerrLehmannAssense opened this issue Oct 27, 2021 · 10 comments
Open

Multiple shell commands in bash= call fail #786

HerrLehmannAssense opened this issue Oct 27, 2021 · 10 comments

Comments

@HerrLehmannAssense
Copy link

While converting my Bitbar configuration to xbar, I figured out that the bash directive is not working as before. I automated my personal tasks with the bash= directive by concatenating several shell commands with &&. For example: changing shell color, setting correct JAVA version, building and starting SpringBoot application. The following plugin code is stripped down the minimum.

XBar Example
---
Tools 
--Test Call|bash="(cd $HOME/Library && ls -l)"|terminal=true

After selection, the menu item, the shell is going to show this

zsh: no such file or directory: (cd $HOME/Library && ls -l)

Enclosed you'll find a simplified version of such a plugin written in perl.

xbarSample.1d.pl.txt

@CyborgSam
Copy link

From the guide:

shell=.. to make the item run a given script terminal with your script e.g. shell=/Users/user/xbar_Plugins/scripts/nginx.restart.sh if there are spaces in the file path you will need quotes e.g. shell="/Users/user/xbar Plugins/scripts/nginx.restart.sh" (bash is also supported but is deprecated)

So putting commands after shell= isn't allowed. I discovered a trick that works (for me). Create a dummy script that does nothing, then pass it a parameter beginning with a ; (semicolon). This "tricks" xbar into executing the parameters. The dummy script goes in a sub-folder of xbar's plugins, it should only have a single line: #!/bin/zsh

Here are your commands setup to use the trick (... is the path to xbar's plugins):
--Test Call | shell='.../subfolder/dummy.sh' | param1='; cd $HOME/Library/; ls -al' | terminal=true"

This is what Terminal shows as the command it received from xbar:
'/Users/sam/Library/Application Support/xbar/plugins/somefolder/dummy.sh' ; cd /Users/ME/Library; ls -al

Some observations about your code snippet (cd $HOME/Library && ls -l):

  1. Putting () around the commands launches them in a sub-shell. For this case it serves no purpose.
  2. In bash and zsh, multiple commands on a single line are separated by ; (semicolon).
  3. && is a conditional. In this case it means do "cd $HOME/Library", if that succeeds then do "ls -l". In this case it works because $HOME/Library always exists (unless your account is really, really messed up...). If the conditional was intentional, a more proper form would be to test the error returned by cd with something like this:
    cd $HOME/Library; [[ "$?" -ne 0 ]] && ls -al || echo "Oops, can't access $HOME/Library."

Clear as mud?

@HerrLehmannAssense
Copy link
Author

@CyborgSam;

Thank you for your reply.

Cyborg Sam> From the guide:

shell=.. to make the item run a given script terminal with your script e.g. shell=/Users/user/xbar_Plugins/scripts/nginx.restart.sh if there are spaces in the file path you will need quotes e.g. shell="/Users/user/xbar Plugins/scripts/nginx.restart.sh" (bash is also supported but is deprecated)

I'm aware, that bash is deprecated and yes, quoting is essential.

So putting commands after shell= isn't allowed. I discovered a trick that works (for me).

I'm not sure, I've contacted Mat and he asked me to file an issue, because he thinks it should work.

Thank you for the trick, I already saw people putting their commands in the plugin, which get executed by passing a parameter, so it knows what to do.

Create a dummy script that does nothing, then pass it a parameter beginning with a ; (semicolon). This "tricks" xbar into executing the parameters. The dummy script goes in a sub-folder of xbar's plugins, it should only have a single line: #!/bin/zsh

Here are your commands setup to use the trick (... is the path to xbar's plugins): --Test Call | shell='.../subfolder/dummy.sh' | param1='; cd $HOME/Library/; ls -al' | terminal=true"

This is what Terminal shows as the command it received from xbar: '/Users/sam/Library/Application Support/xbar/plugins/somefolder/dummy.sh' ; cd /Users/ME/Library; ls -al

Nice trick, but feels it little bit like sql injection ;-)

Some observations about your code snippet (cd $HOME/Library && ls -l):

  1. Putting () around the commands launches them in a sub-shell. For this case it serves no purpose.

I know, I had to strip down my real process, it is much more complex.

  1. In bash and zsh, multiple commands on a single line are separated by ; (semicolon).

Not always, have a look at 3.

  1. && is a conditional. In this case it means do "cd $HOME/Library", if that succeeds then do "ls -l". In this case it works because $HOME/Library always exists (unless your account is really, really messed up...). If the conditional was intentional, a more proper form would be to test the error returned by cd with something like this:
    cd $HOME/Library; [[ "$?" -ne 0 ]] && ls -al || echo "Oops, can't access $HOME/Library."

Clear as mud?

I know how && works. I left this in intentionally, because I wanted to make sure, that if there is a bugfix, it will also work as ; . But after 30 years doing Unix scripting I came across || a few days ago. || is the OR operator. It executes the command on the right only if the command on the left returned an error ;-)

@CyborgSam
Copy link

I'm glad your level of expertise is high, it will help the developers fix this issue.

I use the test && a || b structure a lot when a and b are short statements.

I have no proof of this (didn't check the source code) but it appears xbar isn't parsing either shell= nor param1= correctly. Pass param1="cd $HOME/Library" and the quotes are removed and it becomes two parameters. I couldn't find a way to quote param1 so the quotes survived xbar's parsing.

@matryer
Copy link
Owner

matryer commented Oct 29, 2021

param1="cd $HOME/Library" should indeed set param1 as cd $HOME/Library. If it isn't doing that, we should fix it.

@matryer
Copy link
Owner

matryer commented Oct 29, 2021

image

This test passes, so it looks like it does parse param1 correctly?

matryer pushed a commit that referenced this issue Oct 29, 2021
@CyborgSam
Copy link

CyborgSam commented Oct 29, 2021

Edit: I removed the comments about the script executing in bash. My bad, $SHELL doesn't get set by a script's shebang.

I wrote a zsh plugin to demonstrate the issue (it's still in v2.1.7-beta).
xbarQuotingIssue

Here's Terminal's output (prompt removed):

'/Users/sam/Library/Application Support/xbar/plugins/QuotedParameterTester.15m.sh' This should be quoted.

"/Users/sam/Library/Application Support/xbar/plugins/QuotedParameterTester.15m.sh" called with 4 params:
"This" "should" "be" "quoted." 

When I run the three lines to show theMenuItem:

Open this script in Terminal | shell='/Users/sam/Library/Application Support/xbar/plugins/QuotedParameterTester.15m.sh' | param1="This should be quoted." | terminal=true

Please let me know if I'm doing this wrong or if I can provide further assistance.

@jontelang
Copy link

I have this same issue. A really simple one that fails is:

shell=\"cd $dir; git stash\" 

This generates the same issue. This used to work in BitBar, but now I am struggling. I have giant scripts that have multiple entries which runs commands like this and I am struggling to find a nice solution (having many extra script files seems to remove simplicity I have enjoyed in BitBar).

@jontelang
Copy link

As a workaround I have found that this seems to work:

shell=echo          \
param1=';cd $dir'   \
param2=';git stash' \
param3=';exit'      \
terminal=true       \

@matryer
Copy link
Owner

matryer commented Jul 22, 2022

This is very strange, but that workaround gives us some interesting clues. Thank you.

@nickgnd
Copy link

nickgnd commented Jun 16, 2023

Hey 👋
first of all, great tool! I'm just starting to use it and that's sooo nice! 🙇‍♂️

I had the same issue, I was trying to call a small bash function defined in the same plugin file, like that:

if [ "$1" = 'connect' ]; then
  # do something
fi

echo "🐼"
echo "---"
echo "Connect to VPN | shell='$0' param1=connect terminal=true"

and I was getting this error:

 './vpn.1m.sh' connect
zsh: no such file or directory: ./vpn.1m.sh

where vpn.1m.sh is the name of the script in the xbar plugin folder.

I changed the shell call to use the absolute path and now it works 🎉

echo "Connect to VPN | shell='/Users/nicolo.gnudi/Library/Application Support/xbar/plugins/$0' param1=connect terminal=true"

Hope it helps ✌️
Keep rocking!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants