I am seeing this problem on the trial version of PopClip 2024.3.2 (4516). I’m on macOS 14.4.1.
It’s probably related to the fact that my default shell is /opt/homebrew/bin/fish
. Still, /bin/zsh
exists and works and /bin
is in my PATH
.
I am seeing this problem on the trial version of PopClip 2024.3.2 (4516). I’m on macOS 14.4.1.
It’s probably related to the fact that my default shell is /opt/homebrew/bin/fish
. Still, /bin/zsh
exists and works and /bin
is in my PATH
.
Hi Doug, welcome to the forum. I’d like to look into it. Can you tell me the specific extension this is happening with?
I also tried it with the Say extension:
These Say extensions assume that they can find the zsh
executable in your user PATH. Usually zsh is in /bin
so it should find it if you have /bin
in your path.
If you type echo $PATH
in terminal you can check that.
Another possibility is that /bin
is in your path but zsh
executable does not exist there.
Are either of these the case on your machine?
If zsh is there and the PATH is set correctly, it might indeed be somehting about the default shell configuration. Maybe PopClip is struggling to load the PATH at all. Please could you check the PATH setting & presence of zsh first, and then once that is eliminated I can dig in more deeply.
…Alternatively you can just hardcode an interpreter in the extension via an absolute path though this is of course less portable:
#popclip shellscript example
name: Say
interpreter: /opt/homebrew/bin/fish
shell script: say -v Daniel $POPCLIP_TEXT
The local installation of zsh
seems pretty standard and functional:
dnsimon@blitz ~> zsh
dnsimon@dnsimon-mac ~ %
dnsimon@blitz ~> ls /bin/zsh
/bin/zsh*
dnsimon@blitz ~> zsh
dnsimon@dnsimon-mac ~ %
Using the hardcoded path to /opt/homebrew/bin/fish
indeed makes the installation work. Maybe PopClip simply does not work for a user whose default shell is fish
(which would be a shame).
Let’s dig into it. Here’s the objective-c code that finds the PATH string:
+ (NSString *)userPath {
// get user path
static NSString *result;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (@available(macOS 10.13, *)) {
NSString *const userShell = [[[NSProcessInfo processInfo] environment] objectForKey:@"SHELL"];
NMLogInfo(@"User's shell is %@", userShell);
// avoid executing stuff like /sbin/nologin as a shell
BOOL isValidShell = NO;
for (NSString *validShell in [[NSString stringWithContentsOfFile:@"/etc/shells" encoding:NSUTF8StringEncoding error:nil] componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]) {
if ([[validShell stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] isEqualToString:userShell]) {
isValidShell = YES;
break;
}
}
if (!isValidShell) {
NMLogError(@"Shell %@ is not in /etc/shells, won't continue.", userShell);
return;
}
NSString *const userPath=[self runTool:[NSURL fileURLWithPath:userShell] withArguments:@[@"-lc", @"echo $PATH"]].stringByTrimmingWhitespaceAndNewlines;
if (userPath.length > 0 && [userPath rangeOfString:@":"].length > 0 && [userPath rangeOfString:@"/usr/bin"].length > 0) {
NMLogImportant(@"User's PATH as reported by %@ is %@", userShell, userPath);
result=userPath;
}
else {
NMLogError(@"Path task error");
}
}
});
return result;
}
To break that down:
SHELL
. On my machine:> echo $SHELL
/bin/zsh
and I would guess on your machine that command would return /opt/homebrew/bin/fish
instead.
/etc/shells
and checks if the specified shell is in that list. On my machine:> cat /etc/shells
# List of acceptable shells for chpass(1).
# Ftpd will not allow users to connect who are not using
# one of these shells.
/bin/bash
/bin/csh
/bin/dash
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh
I’m guessing this is the bit where things are going wrong on your machine. Since /opt/homebrew/bin/fish
is not in there, PopClip is noping out at this point.
then PopClip performs a simple sanity check on the purported PATH string to see if it looks like it should
if valid PopClip calls that shell with the script echo $PATH
and captures the output. (It then uses this to find the interprerer via which
.)
So as mentioned above, I’m pretty sure it’s choking at the list of shells. I reckon if you edited that file to add your shell path to the list, then PopClip would be able to use that default shell. (I tried editing mine, i had to use sudo
and a special macOS authenticasion thing but it I could edit it)
So I guess for now that’s the workaround.
I’ll have a think if there is a better way to PopClip to do this so in future it could support a homebrew installed shell out of the box. ATM I’m thinking I could just drop the check against the shell list, which is not really relevant to PopClip. I got that from some example code and it seemed a good idea to keep it. In this particular case, I don’t think calling /sbin/nologin -lc "echo $PATH"
actually does any harm. It just returns with an error status.
Further update: I’ve released beta Build 4575, which drops the /etc/shells check and therefore ought to work on your machine out of the box. When you get a chance to try it, please let me know if it solves it for you.
I updated /etc/shells
to add /opt/homebrew/bin/fish
but it did not help.
I tried with both build 4516 and build 4575.
I logged in with another account on my machine that still has /bin/zsh
as the default account and extension installation worked. So fish
is definitely causing some kind of problem.
Thanks for trying. I’ll try actually installing Homebrew fish as my default shell and see what’s going on.
First of all, fish is a rather nice shell!
Second, I figured out it’s specifically a fish issue. It handles its PATH in a non-POSIXy way, different to other shells, and the PATH variable coming back from it was incompatible with the way I was doing the which
call.
But I do want PopClip to just work regardless of what shell is default.
So I have re-done everything to not explictly depend on the PATH, and instead call every script via the current default shell as “host” executable, with the interpreter and script passed a command to that using the -lc
flags. This means it gets run in the context of a login shell.
In summary, this time it should work, with Build 4578.
Yes, very nice, build 4578 works! Thanks for the quick turnaround on this.