How can I access the "selected_text" variable from Shell script?

The documentation only gives examples on how to retrieve the contents of a string variable in Apple Script and JavaScript.

What is the shell equivalent of:

tell application "BetterTouchTool"

    return get_string_variable "selected_text"

end tell

Use case:

Anyone?

Neither echo ${0} or echo ${selected_text} work?

Sorry the BTT internal variables are currently not available to shell scripts but I'll check if I can somehow make them available.

1 Like

Thanks for the update :call_me_hand:

I think a good solution is to allow the user to set a whitelist of internal BTT variables, and then just pass those as environment variables to the invoked script.

1 Like

Did this ever get implemented? I'm playing around the amazing floating windows that have just been added and would love to be able to make a button that passes the selected text to a python script I wrote a few days ago.

Sorry I really forgot to implement this. I'll add it to the next alpha, you'll then just be able to query the selected_text variable.

For now, you can still do it, here is an example using the "Execute Real JavaScript" action, which speaks the selected text using the "say" command line utility:


(async () => {

// 256 is the identifier of the "save selected text to variable" action
let actionDefinition = {
  "BTTPredefinedActionType" : 256
};

// save the selected text
 await callBTT('trigger_action', {json: JSON.stringify(actionDefinition), wait_for_reply: true});

let selectedText = await callBTT('get_string_variable', {'variable_name': 'selected_text'});

let shellScript = `say ${selectedText}`;

let shellScriptWrapper = {
    script: shellScript, // mandatory
    launchPath: '/bin/bash', //optional - default is /bin/bash
    parameters: '-c', // optional - default is -c. If you use multiple parameters please separate them by ;; e.g. -c;;date
    environmentVariables: 'PATH=/usr/bin' //optional e.g. VAR1=/test/;VAR2=/test2/;
};

let result = await runShellScript(shellScriptWrapper);

returnToBTT(`{BTTMenuItemText: "${x}" }`);
})()


A wait, there is an easier way. Use the "Transform & Copy Selection With JavaScript" action like this:

async (clipboardContentString) => {
  let shellScript = `say ${clipboardContentString}`;

let shellScriptWrapper = {
    script: shellScript, // mandatory
    launchPath: '/bin/bash', //optional - default is /bin/bash
    parameters: '-c', // optional - default is -c. If you use multiple parameters please separate them by ;; e.g. -c;;date
    environmentVariables: 'PATH=/usr/bin' //optional e.g. VAR1=/test/;VAR2=/test2/;
};

let result = await runShellScript(shellScriptWrapper);  
 return "done";
}

(although this version will replace your clipboard content)

Giving it a go now! I mostly used BTT for my TouchBar, and after upgrading to a Mac without one (boo I loved my TouchBar โ€” mostly due to BTT) I wasn't sure it was going to be worth it to buy a lifetime license when my yearly ran out.

I did buy that lifetime license though, since you're one of the most active and responsive developers of any app I've ever used and I figured it would end up well worth it. With these floating menus it's made my license worth every penny!

In just five minutes I've been able to use them to fill at least part of the hole left by TotalSpaces dying (lovely little floating grid to navigate directly to any space) and added several little workflow tweaks that I'm certain will pay dividends! Amazing new addition. I will try your suggestions! Replacing the clipboard is no big issue for now, but I'll definitely look forward to being able to query the selected_text variable when you have time to add it (though no rush given the perfectly viable alternatives you've suggested).

Edit: Somehow managed to write all that without actually saying THANKS!

That's great!
I also think the floating menus have great potential. Just need to work a lot on the documentation :slight_smile:

Thanks, I am also looking forward to using selected text in shell script, the use case for me is that I want to pipe the output of shellscript to vscode.
With javascript I am not sure How do i do that.

the variable is now available - also from javascript you can easily run shell scripts like described here: Using Java Script (not JXA) ยท GitBook

Wow, Do you have an example of that variable ?
I am currently doing the same using Popclip app but that is not extensible, if I can get this to run via BTT, then I can add this to floating menu

random_file="/Users/abc/throwaway/$(openssl rand -hex 8).json"; python3 /Users/abc/python_files/display/GammaCurl.py "$POPCLIP_TEXT" > "$random_file"; code "$random_file"; sleep 1; rm "$random_file"

I think this should work when using the "run real javascript" action. You might need to provide environment variables if the python script depends on some.

(async ()=> {

let selectedText = await callBTT('get_string_variable', {variable_name:'selected_text'})


// put the shell script into a string (single backticks are great for multiline strings)
let shellScript = `random_file="/Users/abc/throwaway/$(/usr/bin/openssl rand -hex 8).json"; /usr/bin/python3 /Users/abc/python_files/display/GammaCurl.py "${selectedText}" > "$random_file"; code "$random_file"; sleep 1; rm "$random_file"`;


let shellScriptWrapper = {
    script: shellScript, 
    environmentVariables: 'PATH=/usr/bin/' //optional e.g. PATH=/test/;VAR2=/test2/;
};

let result = await runShellScript(shellScriptWrapper);
returnToBTT(result)


})();











Thanks for getting back. I tried 2 things and both of them failed to fullfill my usecase

  1. Tried your method which you posted above , The problem is that selected text is getting cut off in between when I try to select the complete JSON request that I am trying to curl. I verified that by just using the below and piping it to vscode to check the selected text
echo "${selectedText}"
  1. Tried to directly use the ${selected_text} variable using the Execute shell script Action, the variable does not seem to work and is not selecting any text.

maybe there is a misunderstanding, this variable does not select text - it contains the currently selected text

Thats my understanding too, so using mouse I select the complete json request which I have in an editor and execute this BTT script.

This can only work if you use the run real javascript action and get the variable value first

let selectedText = await callBTT('get_string_variable', {variable_name:'selected_text'})

Here is a fully working script, which uses the say command to speak the selected text:

(async ()=> {

let selectedText = await callBTT('get_string_variable', {variable_name:'selected_text'})


// put the shell script into a string (single backticks are great for multiline strings)
let shellScript = `say ${selectedText}`;


let shellScriptWrapper = {
    script: shellScript
 
};


let result = await runShellScript(shellScriptWrapper);
returnToBTT(result)


})();











Yes, Sorry if I was not clear earlier. I Used the whole script that you pasted and instead of running my python script, just to check if the selected text is properly being selected or not, i used echo
Here is the script that I run and saw that selected text is getting cut off and it is not selecting the complete text that is meant to be selected, is there some cap on selection?

(async ()=> {

let selectedText = await callBTT('get_string_variable', {variable_name:'selected_text'})


// put the shell script into a string (single backticks are great for multiline strings)
let shellScript = `random_file="/Users/abc/throwaway/$(openssl rand -hex 8).json"; echo "${selectedText}" > "$random_file"; code "$random_file"; sleep 1; rm "$random_file"`;


let shellScriptWrapper = {
    script: shellScript, 
    environmentVariables: 'PATH=MY PATH (Cant share)' //optional e.g. PATH=/test/;VAR2=/test2/;
};

let result = await runShellScript(shellScriptWrapper);
returnToBTT(result)


})();