Mik*_*ke 5 macos bash scripting applescript battery
我正在使用 MacBook,但电池不可靠。我试图找到一个脚本命令,当电池电量低于阈值时,该命令将使笔记本电脑发出哔哔声。经过一些搜索和测试,我在下面找到了一个快速解决方案:
1)我首先创建一个名为 check_battery 的文件,内容如下:
ioreg -l | awk '$3~/Capacity/{c[$3]=$5}END{OFMT="%.3f";max=c["\"MaxCapacity\""]; bat= (max>0?100*c["\"CurrentCapacity\""]/max:"?"); printf("%d", bat)}'
Run Code Online (Sandbox Code Playgroud)
2)然后我创建了以下文件:
\#!/bin/bash
sh check_battery>battery;
let t=60
read a < battery
if(( "$a" < "$t" ));
then
say "Battery level is lower than 60%!";
say "BEAP BEAP"
fi;
Run Code Online (Sandbox Code Playgroud)
3)最后,我尝试将其添加到我的 crontab 作业中,但 crontab 已被 iOS 停止。然后我发现我必须使用launchd,具体如下:https : //alvinalexander.com/mac-os-x/mac-osx-startup-crontab-launchd-jobs
它现在在我的 MacBook 实验室中工作,但可能有更好的解决方案。如果您有其他解决方案,请与我分享。非常感谢。
我认为您的脚本本身就是一个很好的脚本,但在定期运行时最终可能会占用大量资源,因为它会调用一个 shell 进程和两个程序来获取您想要的信息。
在这种情况下,我认为 AppleScript 具有 shell 脚本的几个优点,这主要归功于osascript,它是运行 AppleScript 唯一需要执行的程序,并且它可以在不创建 shell 进程的情况下执行此操作。
这是一个这样的脚本,它可以检索有关计算机电池的信息,并在适当的时候发出警告:
property threshold : 20 -- The level below which the script issues warnings
property verbose : false -- Report current battery level on every run
property file : "/tmp/battery.log" -- The path to the log file (from plist)
set eof of my file to 0
tell the battery()
set warning_level to the warningLevel()
if the warning_level = 1 then return check()
warn about (warning_level - 1) * 5 with alert
end tell
# warn
# Sends out a visible and audible warning with information about the
# remaining charge (+level) on the battery. Invoke without alert to have
# the +level reported in the notification centre as a percentage. Invoke
# with alert to have the +level reported in a pop-up alert dialog as an
# estimation of the remaining battery time (in minutes), and which must be
# dismissed by the user.
to warn about level without alert
if not alert then display notification ¬
["Current battery level: ", level, "%"] as text ¬
with title ["?? Battery Warning"] sound name "Basso"
say "Warning: battery low" using "Moira" pitch 127 ¬
speaking rate 180 without waiting until completion
if alert then display alert ["Warning: battery level is very low"] ¬
message ["Estimated time remaining: " & level & " minutes"] ¬
as critical giving up after 0
end warn
# battery()
# Contains a script object that defines a number of convenience handlers that
# retrieve information about the on-board power source
on battery()
script
use framework "IOKit"
use scripting additions
property warninglevels : ["None", "Early", "Final"]
on warningLevel() -- A ten-minute warning indicator
IOPSGetBatteryWarningLevel() of the current application
end warningLevel
on info()
IOPSCopyPowerSourcesInfo() of the current application ¬
as record
end info
to check()
copy [it, |current capacity|, |is charging|] of ¬
info() to [ps_info, percentage, charging]
if the percentage ? threshold ¬
and it is not charging ¬
then warn about percentage ¬
without alert
if verbose then return display notification [¬
"Percentage: ", percentage, linefeed, ¬
"Charging: ", charging] as text ¬
with title [" Battery Information"]
["Script last run on ", current date, linefeed, ¬
linefeed, __string(ps_info), linefeed] as text
end check
end script
end battery
# __string()
# A that will return an AppleScript record as a formatted string, modified
# specifically for use in this script, therefore may not port very well to
# handle other records from other scripts
to __string(obj)
if class of obj = text then return obj
try
set E to {_:obj} as text
on error E
my tid:{null, "Can’t make {_:", ¬
"} into type text.", ¬
"{", "}", "|"}
set E to E's text items as text
my tid:{linefeed, ", "}
set E to E's text items as text
end try
end __string
# tid:
# Set the text item delimiters
on tid:(d as list)
local d
if d = {} or d = {0} then set d to ""
set my text item delimiters to d
end tid:
Run Code Online (Sandbox Code Playgroud)
它最显着地检索电池剩余电量的当前百分比以及电池当前是否正在充电。
您可以根据自己的喜好安全地更改脚本顶部的三个属性。在verbose模式下,每次运行脚本时都会报告电池百分比和充电状态。如果您按分钟运行脚本,这可能会令人恼火,因此false默认情况下设置为。
但是,当电池电量低于 时threshold,您将收到通知中心的通知,以及 Moira 舒缓的苏格兰语气,它会发出电池电量低的声音警告。
如果电池电量严重不足,您将收到一个弹出式警报,提示您必须自行离开。
该脚本还会返回一堆有关电池的其他信息,一般来说,您不会看到这些信息。但是,如果脚本由launchdplist执行,则返回的信息将记录在日志文件中,您可以在闲暇时检查该文件。
launchdlaunchd提供了一种很好的、具有成本效益的定期运行脚本的方法,并且比创建Stay Open应用程序来轮询数据更可取(这是非常低效的,但在其他场景中也有用途)。
您已经找到了一个很好的链接来描述关于编写.plist文件的基础知识以及如何保存它,然后调用(启动)它。我将在这里总结要点:
创建一个.plist看起来像这样的:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Disabled</key>
<false/>
<key>Label</key>
<string>local.battery</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/osascript</string>
<string>/Users/CK/Documents/Scripts/AppleScript/scripts/Battery.applescript</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>60</integer>
<key>StandardErrorPath</key>
<string>/tmp/battery.err</string>
<key>StandardOutPath</key>
<string>/tmp/battery.log</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)
使用与密钥<string>下的条目匹配的文件名保存它Label。在这种情况下,我将我的保存为local.battery.plist. 我还在 plist 中指定的路径中保存了我的 AppleScript。在我的实验中,launchd如果路径中有任何空格(即使已转义),或者如果我使用波浪号 ( ~) 作为主目录的简写,我感到非常惊讶。因此,我简单地保存了 AppleScript,Battery.applescript并提供了放置它的完整路径。
StartInterval您可以在此处指定脚本运行的间隔(以秒为单位)。就个人而言,我认为 60 秒有点矫枉过正,但我将其设置为用于测试。在实践中,我可能会选择将其设置为 600(10 分钟)之类的值,但您可以判断什么最适合您。
最后的两条/tmp/路径分别是写入错误和返回值的地方。如果更改日志文件的路径,请不要忘记更新fileAppleScript 中的属性。
将 plist 保存或移动到目录中~/Library/LaunchAgents/。
从终端使用以下 shell 命令加载它:
launchctl load ~/Library/LaunchAgents/local.battery.plist
Run Code Online (Sandbox Code Playgroud)如果稍后对.plist或进行任何更改.applescript,请记住卸载然后重新加载launchctl:
launchctl unload ~/Library/LaunchAgents/local.battery.plist
launchctl load ~/Library/LaunchAgents/local.battery.plist
Run Code Online (Sandbox Code Playgroud)成功加载.plistinto 后launchd,它应该立即运行 AppleScript 并将返回的数据写入日志文件。这是我的/tmp/battery.log文件的输出:
Script last run on Tuesday, 1 January 2019 at 22:01:52
is present:true
is charged:true
power source state:"AC Power"
Current:0
max capacity:100
DesignCycleCount:1000
current capacity:100
name:"InternalBattery-0"
battery provides time remaining:true
is charging:false
hardware serial number:"D8663230496GLLHBJ"
transport type:"Internal"
time to empty:0
power source id:4391011
Type:"InternalBattery"
BatteryHealth:"Check Battery"
time to full charge:0
Run Code Online (Sandbox Code Playgroud)
第一次电池信息非常有趣,但对于大多数用例来说可能是多余的。(这就是说,我刚才注意到它的建议我"Check Battery"下BatteryHealth,所以现在我很高兴我把额外的数据)。
无论如何,如果额外数据不是您认为自己需要的东西,我已经看到user3439894留下的评论,它提供了一种非常好的、紧凑和简单的方法来检索有关电池的更显着信息,即百分比级别和无论是否充电。这可以说是比我的 ObjC 方法更合适的 AppleScripting 解决方案,它会带来很小的开销,而且可以制作更短的脚本。
现在,我坚持我的,因为我显然有电池健康问题,可能应该解决这个问题。
我看到你的问题并尝试编写一些代码。
这是AppleScript:
on run
set theBattString to (do shell script "pmset -g batt")
-- the above will return something like...
-- Now drawing from 'Battery Power' -InternalBattery-0 82%; discharging; 4:06 remaining
set batteryLevel to splitText(theBattString, space)
--I used this line under for counting the number of items in batteryLevel.
--Then I get the right item for the time remaining.
--It is a static value for me it was item 9.
--set totalItembatLvl to length of batteryLevel
tell application "System Events"
set remainingTime to item 9 of batteryLevel
if remainingTime < "3:10" then
display alert "low battery " & remainingTime & " before shut down."
--batteryLevel & " " & remainingTime
end if
end tell
end run
on splitText(theText, theDelimiter)
set AppleScript's text item delimiters to theDelimiter
set theTextItems to every text item of theText
set AppleScript's text item delimiters to ""
return theTextItems
end splitText
Run Code Online (Sandbox Code Playgroud)
您可以将其保存为空闲应用程序,它会每分钟检查一次电池电量。
on idle
set theBattString to (do shell script "pmset -g batt")
-- the above will return something like...
-- Now drawing from 'Battery Power' -InternalBattery-0 82%; discharging; 4:06 remaining
set batteryLevel to splitText(theBattString, space)
--set totalItembatLvl to length of batteryLevel
set remainingTime to item 9 of batteryLevel
if remainingTime < "2:40" then
display alert "low battery " & remainingTime & " before shut down."
--batteryLevel & " " & remainingTime
end if
return 60
end idle
on splitText(theText, theDelimiter)
set AppleScript's text item delimiters to theDelimiter
set theTextItems to every text item of theText
set AppleScript's text item delimiters to ""
return theTextItems
end splitText
Run Code Online (Sandbox Code Playgroud)
告诉我你的想法,也许其他人可以改进这个答案。
问候。
[编辑]
感谢用户@user3439894提供了适合您需求的相关代码。
set batteryPercent to word 6 of paragraph 2 of (do shell script "pmset -g batt")
if batteryPercent < 40 then
beep
repeat 3 times
say "Attention " & batteryPercent & "%" & " before shut down."
end repeat
end if
Run Code Online (Sandbox Code Playgroud)
就像我的第 2 个代码一样,您可以将其放入空闲应用程序中。
on idle
set batteryPercent to word 6 of paragraph 2 of (do shell script "pmset -g batt")
if batteryPercent < 40 then
repeat 3 times
beep
say "Attention " & batteryPercent & "%" & " of charge before shut down."
end repeat
end if
return 60
end idle
Run Code Online (Sandbox Code Playgroud)
问候