I'm using this BetterTouchToll for make my touch bar more interesting, what is very cool.
He accept some Apple Scripts for more dynamic, so I start to study this scripts.
Now I wanna to display my Magic Mouse Battery on my touch bar, for this I was trying this code, but is not working.
if application "Mouse" is running then
tell application "Mouse"
return (get Battery)
end tell
end if
return "no mouse"
My guess is that Mouse is not a application, but don't know what to put in the place
The traditional means of getting the battery level is to use ioreg on the command line. However, the traditional means of doing this no longer seem to work as of at least macOS High Sierra/10.13.4; that is, they no longer allow choosing to display just the battery percentage of a single bluetooth device.
So this is a hack that assumes that the Magic Mouse is always the last device displayed by ioreg. This is likely to fail, if not across different installations of macOS, then across different versions.
ioreg -c AppleDeviceManagementHIDEventService | grep BatteryPercent | tail -1 | sed 's/[^[:digit:]]//g'
In an AppleScript, this would be:
do shell script "ioreg -c AppleDeviceManagementHIDEventService | grep BatteryPercent | tail -1 | sed 's/[^[:digit:]]//g'"
You have your code setup to also detect when the Magic Mouse is not connected. The product name is in the property “Product” in ioreg. For example:
ioreg -c AppleDeviceManagementHIDEventService | grep '"Product" ='
So to make sure that this final device is the Mouse, you could do:
set finalDevice to do shell script "ioreg -c AppleDeviceManagementHIDEventService | grep '\"Product\" =' | tail -1"
if finalDevice contains "Magic Mouse" then
set remaining to do shell script "ioreg -c AppleDeviceManagementHIDEventService | grep BatteryPercent | tail -1 | sed 's/[^[:digit:]]//g'"
remaining & "%"
else
"no mouse"
end if
The basic logic:
Grab the list of all products using ioreg.
Use tail to get only the final product in the list.
If the final product is a Magic Mouse, then:
Grab the list of all battery percentages using ioreg.
Use tail to get only the final battery percentage in the list.
Use sed to get only the actual number from that line.
Append a percentage symbol to the number.
Otherwise, there is no mouse. (Or the mouse is not the final item in the list.)
For the older means of using ioreg, see, for example:
Reporting on Bluetooth Mouse/Keyboard battery status
Read Magic Mouse and Apple Wireless Keyboard Battery percentage
Thanks so much for the solution. Very inspiring. As I have multiple devices I made my own script based on your solutions. I want to share it here in case it could be useful to others.
As I have more than one bluetooth device, the order of them in ioreg is based on the order they were connected. Which means I cannot assume that the mouse is the last device.
I made most of it in shell, not in applescript, since I am more experienced in shell and therefore it was quicker that way. Using Applescript for filtering the output from ioreg would properly have been a 'cleaner' solution :p
WARNING: I know this code is pretty crappy, but it was quick to write and it does the job, don't assume this to be a way of doing things properly.
My solution
From BTT the following script calls the shell script
set devicename to "Magic Mouse 2" -- The name of the device in ioreg
set displayname to "Mouse" -- The name to display on the touchbar
set remaining to do shell script "~/.dotfiles/shell/device_battery_level.sh" & " " & quoted form of devicename
if remaining is "" then
"" --No device present = no output to touchbar
else
displayname & " " & remaining & "%" -- Show output on touchbar
end if
As seen the code pretty much just calls the shell script. The name provided in the variable "devicename" is used as a argument to the script and is the name that the script will look for in ioreg. If the shell script outputs an empty script no widget will be displayed. For me this was preferred over displaying "No device".
The script in "~/.dotfiles/shell/device_battery_level.sh" then looks like this:
#!/bin/sh
DEVICES=$(ioreg -r -l -n AppleHSBluetoothDevice | egrep '"BatteryPercent" = |^ \| "Bluetooth Product Name" = ') #Lets get a list of all bluetooth devices
DEVICELINE=$(grep -n "$1" <<< "$DEVICES") #$1 is the device that this script was called with. Lets extract only the line with that device
if [$DEVICELINE = ""] #If DEVICELINE is empty the name of the device was not in the output and it is properly not connected.
then
echo "" #Device not present, lets give BTT an empty string
else
LINENR="${DEVICELINE:0:1}" #Then we find out where the line of the device is located
NEXTLINE=$(expr $LINENR + "1") #The battery level is at the next line therefore we increment the line number
SEDCOMMAND="p"
BATTERYLINE=$(echo "$DEVICES" | sed -n $NEXTLINE$SEDCOMMAND) # Now we can extract the line with the battery percent
echo $BATTERYLINE | sed 's/[^[:digit:]]//g' #Finally we just need to get the digit and echo that to BTT
fi
The basic logic is the same as the above answer. Except instead of grabbing the last line from ioreg with tail egrep is used to only output relevant lines. The egrep code is based on another post here: https://apple.stackexchange.com/questions/293502/how-can-i-determine-the-battery-level-of-my-magic-mouse-from-the-command-line/293505#293505
Based on this the line which mentions the devicename is found. The logic is that since the battery level information is always below the devicename in ioreg the next line in the extracted list must be the battery level.
Related
little stuck atm with figuring out how to script an answer to a bash arrow selection menu
Basically my question is how do I script selection of an item based on name?
I do know that I can use the following command to select an option by index and this is as close as I've gotten but I think there's a way to select it by name instead
echo 5 | zapier link
Important notes:
When a version is already selected it gets the [currently linked app] at the end of the version, this needs to be taken into account in text search
The numbers in () i.e (142900) is important
Pretend the name that's blocked out in red is testOver
I would prefer not to have to install any tools to accomplish this, only use whats built into bash unless there's no other option.
Thanks in advance for your help!
To select a menu entry by search, you have to read zapier's output. Usally this would be a job for expect, but since you don't want to install anything, try the following:
mkfifo fifo
zapier link <fifo |
awk '/Which integration/ {m=NR}
m && /\(142900\)/ {print NR-m; fflush(); m=0}' >fifo
rm fifo
This selects the option containing the string (142900). Of course you can adapt the regex to select any other option. Also consider replacing /Which integration/ by the full title of the menu to make detection safer.
If you want to see the output of zapier, use | tee >(awk ... >fifo).
In case zapier behaves differently when running inside a pipe, run it inside a pseudo-terminal. If zapier buffers its output for pipes, using script or stdbuf to unbuffer the output is an absolute requirement. Otherwise the entire command may run into a deadlock.
script -qec './zapier link' /dev/null <fifo # on Linux
script -qe /dev/null ./zapier link <fifo # on BSD/macOS.
Unfortunately, awk does not know when the menu is fully printed, so it cannot look at all the options first and then decide afterwards, but has to select one option as soon as it sees it. If there is no such option, the script gets stuck. To solve this you could replace awk with a small bash script:
zapier link <fifo | while IFS= read -r ln; do
[[ "$ln" = *"Which integration"* ]] || continue
IFS=$'\n' read -rd '' -t1 -a opts
# insert code to pick an option from the array `opts`
# either `echo "$((i+1))"` to select option `${opts[i]}`
# or `break` to select no option
done >fifo
Is it possible to have a bash script split the terminal window horizontally at one point, so that the left side details the overall progress of tasks, and the right side contains verbose output from the current task being run?
I've found some people referencing nohup and screen in contexts of splitting the terminal window, but I don't know how to get that going in a bash script sense, or if its even the right direction for my needs.
At the moment, I've got lots of long tasks with long output, so I'm sending the output of each to a cumulative log file, instead of dumping on the screen. Then, as an interim, manually opening a new terminal window to use watch tail LogFile* to keep an eye on what's going on.
It would be great if I could automate that process.
Update
Some leads.
This post and its comments were very helpful, to establish that you can launch a command in one window and send its output to another based on its pts value.
For example, ls > /dev/pts/7 will display output of ls in the terminal window at pts/7.
Still stumped about how to automate splitting the screen programatically, and using that, instead of a new window.
I got a working example going with Terminator.
Start the bash script below in a new Terminator window:
terminator --command="bash /path/to/script"
And once we're running in that, it's a bit of a hack solution, but to split the screen by command-line in the bash script, I ended up using xdotool to send keybindings to Terminator. Like so:
#!/bin/bash
# send keybinding that splits screen vertically
xdotool key Ctrl+Shift+E
# Terminator now sets focus to the right side (the new split) by default, so send keybinding that returns the focus to our left side
# sleep a tiny little bit first
sleep 0.01
xdotool key Alt+Left
# now to send output to the right side, let's work out "where" the ride side is
# use who to find the pts ids of all currently spanwed terminal windows
# use tail to find the last line from who (which we assume is the terminal window we just split)
# then grep to find just the number after pts/
## windowID=$(who | tail -n1 | grep -oP 'pts/\K[0-9]*')
# updated this to fix bug where who does not return pts values
# https://askubuntu.com/questions/1110203
windowID=$(ps -u $USER -o tty | awk 'NR>1 && $1 != "?" {a[$0]++};END{for(val in a) print val}' | tail -n1 | grep -oP 'pts/\K[0-9]*')
# now we can send output from commands to the right side split window by using its pseudo device id. for example:
ls -lah >> /dev/pts/$windowID
exit
I am currently looking to use "diskutil cs list" to show the logical volume groups. I need to be able to isolate the UDID.
Example line from "diskutil cs list"
+-- Logical Volume Group B848BCC7-6FFA-4643-AFE1-56FCA333A6B5
Previously my though process was to;
diskutil cs list | grep 'Group'
I think AWK will be a better route to show just the string of letters and numbers. I have been unsuccessful in finding out how to dow so
Ultimately, i will use the UDID in a shell script for reformatting a Fusion drive. Using something similar to below.
set a to (do shell script "diskutil cs list|grep 'Group'")
I'd like it to set a to the UDID and not the full line.
Try:
diskutil cs list | awk '/Group/{print $NF}'
/Group/ will look for lines that have the word Group in them. It is just a filter mechanism. If all your output lines have Group in them, then you can remove /Group/ part.
Once it finds those lines, it will print the last element of that line. awk by default splits the line on space.
Depending how new your system is you might have lsblk(1) command, that is made to be combined with scripts. The utility can limit what block devices are listed, and what information is displayed in format that can be defined.
diskutil cs list | grep -Po 'Group \K\S*$'
I use Alt-! (Alt-Bang) a lot in Emacs. One of the big things I use it for is
Alt-! cat $logfile | grep 'this' # show me one kind of event
or sometimes
Alt-! cat $logfile | grep 'this' | wc -l # count that one event's occurrences
Two things:
1) No tab-completion from this prompt: why not?
2) What if instead of $logfile, I want to scan one of the Emacs buffers?
To scan an Emacs buffer, use M-| instead of M-!: it passes the region as input to the command. Use M-1 M-| if you want the output of the command to replace the region.
For the particular command you mention, use M-x grep if you want to see all matches. Or you can open it and see the matches with M-x occur.
Alt-| does is shell-command-on-region
with a(ny) numeric prefix (e.g. C-u 1 Alt-|) the region is replaced by the result, otherwise that appears in new buffer
I was just wondering how someone would go about finding all the applications that are installed on Mac OS X 10.5 using preferably applescript and output all their application names to a text file.
All the applications installed under Mac OS X are registered in the Launch Services database.
The Launch Services framework contains a helper shell command lsregister which among other uses can dump the information stored in the Launch Services database. Under Mac OS X 10.5 and 10.6 that command is located in the following folder:
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister
Using a few simple grep filters one can extract the full paths of all registered applications:
lsregister -dump | grep --after-context 1 "^bundle" | grep --only-matching "/.*\.app"
Putting it all together, the following AppleScript will compute the user visible names of all registered applications using the info for command:
property pLSRegisterPath : "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister"
set theAppPaths to every paragraph of (do shell script pLSRegisterPath & " -dump | grep --after-context 1 \"^bundle\" | grep --only-matching \"/.*\\.app\"")
set theNames to {}
repeat with thePath in theAppPaths
try
copy displayed name of (info for (thePath as POSIX file)) to end of theNames
end try
end repeat
choose from list theNames
There are a few methods in this post, depending on how in-depth you want your search to be. Also not sure if that's exactly the output format you want, but you can probably tweak it for your specific needs.
I use the system_profiler command to get my text. Then you can parse as needed.
system_profiler SPApplicationsDataType
...
AppleScript Utility:
Version: 1.1.1
Last Modified: 5/18/09 10:34 PM
Kind: Intel
64-Bit (Intel): Yes
Location: /System/Library/CoreServices/AppleScript Utility.app
maybe pipe it to a text file and then use sed ....
Bash commands can be called through applescript if you want to have an application or you can save the script with a .command extension and the user will be able to double-click on it.
For poeple like me using bash scripting to reach their goals here is a bash variant of the script:
#!/usr/bin/env bash
path='/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support'
$path/lsregister -dump | grep -A 1 "^bundle" | grep --only-matching "/.*\.app" | awk -F "/" '{ print $NF }' | awk -F "." '{ print $1 }'
This gives a list of all apps without the .app extension.