Probably I'm missing something obvious here, but I can't seem to figure out what.
I'm attempting to make a macro that will prompt me with a list from my Terminal command history, then pass the selected command wholesale into an Execute Shell Script action (which will display the results in a window). There are a couple snags, one of which is that the KM shell script action cannot handily execute commands from non-native packages (e.g. echo works fine, but brew does not); however, I have some ideas to solve this.
My bigger issue at the moment, though, is with spaces, particularly if there's a path in the selected script. For example, I might like to search for and execute something like tail -n 2 'Users/hemi/Library/Logs/Keyboard Maestro/Engine.log' and have the results displayed in a KM window, but saving that text to a variable that is then inserted into the Execute Shell Script action results in the following error:
2025-01-15 16:39:24 Execute a Shell Script failed with script error: tail: 'Users/hemi/Library/Logs/Keyboard: No such file or directory
tail: Maestro/Engine.log': No such file or directory. Macro “.Terminal shell command results in window PROMPT WITH LIST?” cancelled (while executing Execute Shell Script).
I've tried various alternatives such as using double quotes and escaping the space with a \ rather than wrapping the path in quotes at all. All seem to result in the same error. I know there are issues with passing quotes and have consulted the wiki page. I tried using find/replace to replace the single quotes with single quotes wrapped by double quotes, but that didn't work (nor did I really expect it to ). The macro is attached below and includes some samples from my history file for demonstrative/testing purposes. Although just maybe there's an even simpler approach that I've utterly failed to see.
N.b. I also tried using With input from: Variable in the shell script action, but that didn't do what I thought it might and no shell script was executed without the $KMVAR as well. (The uploaded macro still has this set because I forgot to change it back.)
One way to avoid the whole issue of spaces is to stop using the option "Execute text script" in the "Execute Shell Script" action and change it to "Execute script file." This will guarantee you won't have any problems with spaces. You just have to put your command into a (temporary) file and then execute it. But there are probably other ways to solve this, and perhaps other people will chime in.
That should work fine -- as long as your KM ENV_PATH variable is set up correctly.
But there are more general problems with what you're doing, many of which are explained in this post for example. You'll find plenty of similar discussions out on the interwebz. And there's a whole section on this in the Bash FAQ.
You should also tread very carefully -- taking a command from one context and trying to run it in another could succeed, fail silently, or even completely hose your entire system! Is it really worth the risk when you could just use Terminal and its command history anyway?
Thanks, I will certainly explore these resources further.
I'm only looking to execute commands with explicitly static information output (e.g. tail x-lines of KM log, vmmap summary of a given process, etc) as opposed to commands that make system changes. I also want to automatically exclude such commands from the prompt list, but I needed to make sure what I'm trying to do is actually feasible. The reason being is that terminal windows breed like dust bunnies in my (severely limited MBA) workspace and I frequently lose track of the relevant windows I'm actively trying to work from, and I'm hoping this is a solution that can help mitigate that because currently I do just have to open a new terminal window to grab this or that that I'm looking for.
Thanks, Peter. I have been reading the wiki page, and my apologies if I'm misunderstanding you, but the examples there only ever have the KM variable as a part of the shell command (as in your comment), and I'm trying to do something a bit different where I save the entire command to a variable that is then passed to the action.
In case I was unclear in my first post, I'll summarise my objective step-by-step:
Prompt with List populated by the file ~/.zsh_history to give list of terminal command history
Select a previously run command from the terminal command history
Save the selected command as text to a KM variable (e.g. LocalCommand = tail -n 2 'Users/hemi/Library/Logs/Keyboard Maestro/Engine.log')
Use the text from that variable in the Execute Shell Command action to have results displayed in a window (e.g. $KMVAR_LocalCommand)
My assumption is that $KMVAR was not designed to be used in this way, but I'm really hoping to find a workable solution for this case.
But doesn't each window (session) have its own command history? Or have you set zsh to use shared history?
It's easy enough to set up a bunch of static KM macros for regularly used commands. But for history-based ones I think I'd leverage what Terminal already provides -- using KM/AS to automate collection, choice, and the spawning of a new Terminal window to display the result of the command.
It's that the shell is not designed to interpret variables "in this way". Quotes in variables are just ordinary characters and don't have the "treat spaces as spaces, not argument separators" meaning that "standard" command line double-quotes do. This is what makes things so tricky -- you'll effectively have to parse your command to work out what's a separator and what isn't. It's also why suggested solutions in the links above all hedge with "might work for simple commands" and similar.
I think you missed my point. If you replace the variables with their values when you create the file, you avoid the issue in the Execute Shell Script action.
I considered this, or rather I considered having a prompt with list populated with manually configured commands, but, while there are certainly commands I do use regularly, others are erratic/unpredictable/unknowable to me in advance, which is why I'd really like to have the flexibility of quickly searching my terminal history without having to open yet another Terminal window. This is also why I don't often/ever use the built-in Alfred function to execute shell commands—it launches a new Terminal window (and it's slow).
Ah, no wonder I was having difficulties. For whatever reason, I just didn't think to look for it in Settings -> Variables and it wasn't even there anyway. I've added it and set it to my $PATH, which does indeed solve that issue. Double thanks.
Getting the right level of quoting for everything in a situation like this is virtually impossible.
OK, you are in trouble before you start then I suspect.
My ~/.zsh_history has multiline commands in it, for example a line is:
while [ $i -le 1000 -a $(($(echo $(/bin/ps -xp 19012|/usr/bin/wc -l)))) -gt 1 ]; do\
But that is part of more lines, so it would not be valid on its own.
But ignoring that, and assuming the history line has a valid command in it, then yes, writing it to a script file and executing the file would be the way to go - putting it in a variable will never work because the shell quoting and interpolation does not happen recursively.