macos
🍏 «Сиерра»
Ну слушайте, когда был жив Тот Мужик, такого не было. Скачал себе сегодня «Сиерру» — новую версию операционной системы для «Маков». Начался процесс установки.
Через
Выкручиваться пришлось через шелл (из верхнего меню можно запустить «Терминал»), я нашёл свой диск, перемонтировал его в режиме для записи и удалил
mount -u -w /dev/disk1
cd '/Volumes/Image Volume/Users'Дальше переходите в домашнюю папку вашего пользователя и удаляете
👁 Глаз следящий
Обновилась до версии 2.9 моя любимая
Протокол довольно простой:
ESC ] 1337 ; File = [необязательные параметры] : изображение в формате base64 ^GРешил немного с ним побаловаться, результат на скриншоте — небольшая программа на «баше» — глаз, который следит за указателем мыши.
Пришлось разобраться с тем как вообще получают координаты мыши в консоли, плюс вспомнить школьную геометрию. Синусы, косинусы, вот это всё, неявно вычисляются через awk и используются для определения где нужно рисовать зрачок.
Чем дальше курсор находится от глаза, тем больше событий мыши получает консоль во время перемещений по окружности вокруг него.
Для запуска требуется iTerm2 2.9 и выше и Imagemagick.
Подпилил переподсоединялку вайфая
Чуть поменял «переподсоединялку вайфая» для Мака — теперь пингуется не 8.8.8.8 (это ДНС Гугла), а адрес гейта, что более надёжно. Правда с конца октября, когда я её написал много воды утекло — вайфай у меня отваливается теперь очень редко, уж не знаю что изменилось.
Переподсоединялка вайфая

Вышло очередное обноление «Эль Капитана» на «Маке», а проблема с вайфаем на «Макбуках Про» так никуда и не делась. Я планирую
В общем, сделал себе на «Баше» утилиту переподключающую вайфай при пропадании пингов до 8.8.8.8 (это ДНС «Гугла»). Сегодня уже целый день её использую, так гораздо комфортнее.
Блокировка экрана на «Маке» из Си
CGSCreateLoginSession(NULL);
// теперь выдаёт
// Assertion failed: (sid != NULL), function CGSCreateLoginSession, file Services/Connection/CGSSession.c, line 418.Возможно
В общем, покапался я в заголовочных файлах, подбором и интуицией родил код, который блокирует экран
// получаем словарик с атрибутами текущей сессии
CFDictionaryRef dict = CGSCopyCurrentSessionDictionary();
// выбираем из него идентификатор текущей сессии, получаем его в виде int
CFNumberRef number = (CFNumberRef) CFDictionaryGetValue(dict, CFSTR("kCGSSessionIDKey"));
CGSSessionID currentSession;
CFNumberGetValue(number, kCFNumberIntType, ¤tSession);
// блокируем текущую сессию
CGSCreateLoginSession(¤tSession);Обновлённая версия лежит там же — на «Гитхабе».
«Эль-Капитан»
Никогда в жизни не ставил
В общем, поставил себе третью бету
Tcl/tk и Retina
О, оказывается, можно «ретинизировать» интерпретатор Тикля — сделать так, чтобы программы на этом языке хорошо смотрелись на маковской ретине (см. скриншот).

Для этого нужно скачать программу Retinizer и бросить в неё Wish.app, который находится в /System/Library/Frameworks/Tk.framework/Versions/Current/Resources/
Говорящие часы

Вот очень правильная настройка есть в «Маке» (немногие её включают, а зря!) — компьютер может произносить текущее время каждый час, полчаса или четверть часа. Пользуюсь ей давно, помогает быть продуктивнее в работе.
По кнопке «Настроить голос…» открывается меню, в котором можно выбрать русский голос, если это требуется.
Если у вас «Мак», рекомендую включить эту настройку!
Русские имена на «Маке» после разархивации ZIP
Я вчера скачал несколько десятков

Эта давнишняя проблема «Мака», проистекающая из родовой травмы
Как бы там ни было, в конце индикатора прогресса я увидел кучу файлов с нечитаемыми именами. Ничего готового я быстро не нашёл, поэтому сварганил небольшой скрипт на «баше», который восстанавливает русские имена разархивированного
Способ употребления такой: складываете всё испорченное
Как ускорить Yosemite
«Йосе́мити» — худшая по стабильности операционка Эпл из всех, которые я
Я почитал в сети советы бывалых по ускорению её работы,


Удаляем раскладку «США» («U.S. English») из Mac OS X 10.9 («Maverick») ★
Как стало известно ещё на этапе появления ранних сборок «Маверика», раскладка «США» не удаляется из неё способом, который описал Артём Поликарпов (а я написал скрипт, автоматизирующий этот процесс).
Зато читатели в комментариях к скрипту указали на другой, очень несложный способ сделать то же.
Напомню в чём проблема. Лично я использую для работе на «Маке» раскладку Бирмана.
После установки раскладки Бирмана, раскладок становится три: русская Бирмана, английская Бирмана и системная — «США». Последняя явно лишняя, но система удалить её не позволяет. Её удаётся удалить только в обмен на установку любой другой системной раскладки.
Но есть баг, спасибо ему, что он существует.
Нужно поставить японскую раскладку «котоэри», потому удалить раскладку «США», потом «котоэри». В системе останутся только две раскладки Бирмана.
Уходим с телефоном, «МакБук» выключается
Причина, по которой я засел за Пайтон и стал изучать как из него работать с Bluetooth в том, что мне очень хотелось сделать следующую вещь: как только я покидаю рабочее место, мой ноутбук блокируется.
Идея выглядела просто: надо посмотреть присутствует ли в эфире мой смартфон, если нету, значит я
В общем, всё получилось у меня. Если хотите, чтобы у вас работало так же, то двигайтесь по шагам.
Шаг №1.
Нужно узнать так называемый «адрес» вашего устройства и привязать его к компьютеру. Тут ничего сложного нет, заходим в настройки «Блютуз» на «Маке» (они находятся в «Системных настройках»), привязываем его как обычно и переписываем себе 12 букв, разделённых минусами, это и есть адрес:

Шаг №2.
С этого шага потребуется уметь пользоваться терминалом. Создаём запускаемый файл
#!/usr/bin/python
import objc
import sys
from subprocess import call
objc.loadBundle('IOBluetooth', globals(), bundle_path=u'/System/Library/Frameworks/IOBluetooth.framework')
def CheckDevice(address):
dev = IOBluetoothDevice.withAddressString_(address)
if dev.isConnected():
return True
conn = dev.openConnection()
if conn == -536870185: # Bluetooth is off
return True
if conn == 0:
dev.closeConnection()
return True
return False
cmdtorun=(r'/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/CGSession', r'-suspend')
try:
if not CheckDevice(sys.argv[1]):
call(cmdtorun)
except IndexError:
print("Usage: bt-lock <device address>")В скобках замечу, чтобы сделать файл запускаемым нужно в терминале выполнить следующую команду: chmod a+x
Шаг 3.
Создаём файл ~/Library/LaunchAgents/ru.bolknote.Bluetooth-lock.crontab.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>Label</key>
<string>ru.bolknote.Bluetooth-lock.crontab</string>
<key>Program</key>
<string>/usr/local/bin/bt-lock</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/bt-lock</string>
<string>а̲д̲р̲е̲с̲ ̲в̲а̲ш̲е̲г̲о̲ ̲у̲с̲т̲р̲о̲й̲с̲т̲в̲а̲</string>
</array>
<key>Nice</key>
<integer>20</integer>
<key>StartInterval</key>
<integer>30</integer>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>И выполняем в терминале команду «launchctl load ru.bolknote.Bluetooth-lock.crontab.plist». Это всё.
Чтобы отключить всю эту марахайку, достаточно выполнить в терминале команду «launchctl unload ru.bolknote.Bluetooth-lock.crontab.plist» или выключить Bluetooth на ноуте.
Решение только для «Мака», как работать из Пайтона с Блютузом под другие операционные системы, я не знаю.
Превращение маковской флешки в полноценную
Как, наверное, многие знают, при покупке ноута «МакБук», в коробке лежит

Оказывается, есть способ превратить её в полноценную, перезаписываемую флешку! Для этого, правда, понадобится компьютер с Виндой или хотя бы виртуальная машина. В моём случае это был старенький ноут с нужной операционкой. Винда вам нужна, чтобы запустить утилиту sm32Xtest, которая и вразумит ваш «сидиром».
После запуска, если утилита не нашла вставленную флешку, нужно нажать «F5», в этом случае, произойдёт скан всех

Если эта операция выполнилась успешно, надо нажать клавишу пробела и дождаться выполнения всех оставшихся операций. Если всё прошло хорошо, в строке статус сменится на «Pass», а справа появится большая надпись «OK»:

После этого можно флешку извлекать (не забудьте извлечь её безопасно). У меня получилась флешка в 8ГБ:

Как очистить контексное меню «Открыть с помощью…» в «Маке»
На «Макрадаре» появилась статья о том как очистить контекстное меню «Открыть с помощью…» на «Маке». Для меня загадка почему это так, но после установки программ и обновления их версий в нём остаются дубли. Например, у меня там несколько «Опер», парочка «Икс Кодов» и так далее.
Чтобы избавиться от дублей, нужно запустить в «Терминале» следующую команду:
/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister \
-kill -r -domain l -domain s -domain uОна не делает ничего опасного, лишь чистит это меню (опция «kill»), потом рекурсивно («r») проходится по локально установленным программам («domain l»), программам системы («domain s») и программам, установленным только для текущего пользователя («domain u»), и добавляет нужные из них в контекстное меню.
Удаляем расладку «U.S. English» из «Мака»
Артём Поликарпов написал рецепт как можно удалить из «Мака» раскладку «U.S. English». Она очень мешается и совершенно не нужна, если поставить великолепную раскладку Ильи Бирмана (кстати, если вы
Но рецепт Артёма мне не нравится тем, что для его выполнения приходится иметь у себя редактор Xcode, который ещё и несколько гигабайт весит. Поэтому я, как водится, написал скрипт, который нужно выполнить из «Терминала» (после его выполнения придётся опять залогиниться в систему) и ненужной раскладки уже не будет.
Какое счастье!
Проще всего скрипт запускать из «Терминала» вот так:
bash <(curl -fsSkL raw.github.com/bolknote/shellgames/master/us_layout_remover.sh)Чтобы вернуть всё обратно достаточно запустить программу ещё раз.
Добавлено позднее: удалению раскладки может мешать Punto Switcher.
Проблема с wifi-иконкой в «Montain Lion»
У меня с апгрейдом системы до «Горного Льва» возникла нестрашная, но раздражающая проблемка — несмотря на то, что соединение с вайфайем есть и сайты открываются, «Мак» утверждал, что подключение к интернету отсутствует и показывал иконку вайфая в верхнем меню с восклицательным знаком.
Меня это раздражало, потом и на ноуте жены возникла та же проблема. Поискал в интернете, все спрашивают совета, но никто не предлагает решение.
Решение нашёл случайно — надо удалить все лишние сетевые устройства (кнопкой с минусом в «Настройках сети»), у меня там была целая куча «свистков» МТС, «Мегафона» и «Билайна», у жены — то же.
Удалил устройства, восклицательный знак в иконке вайфая пропал. Потом устройства можно добавить обратно, это уже ни на что не влияет.
Настройка «Сообщений» в «Горном Льве» на работу с «аськой»
В «Горном Льве» («Montain Lion» — это новая версия «Макоси», которая появилась сегодня) есть новая программа — «Сообщения» (Messages), это встроенный в операционную систему
ICQ в списке нет, но тем не менее, настроить «Сообщения» для работы с этим протоколом можно — в «аське» используется тот же протокол, что и в AIM — «Оскар», надо только поменять данные сервера, с которым надо соединяться и убрать галочку «Использовать SSL»:

Чтобы отключить HTML, который «Сообщения» отсылают по аське, нужно выполнить следующую последовательность действий:
# 1) в «Терминале» выполняем:
defaults read com.apple.iChat.AIM | sed "s/\(ForceICQPlainText\).*/\1 = 1;/" | xargs -0 defaults write com.apple.iChat.AIM
chflags uchg ~/Library/Preferences/com.apple.iChat.AIM.plist
# 2) !перезагружаемся!
# 3) в «Терминале» пишем:
chflags nouchg ~/Library/Preferences/com.apple.iChat.AIM.plistИнтерактивная игра на bash: «Арканоид» ★
После шахмат, где я решал проблему опроса клавиатуры, мне захотелось попробовать сделать
Забегая вперёд, скажу, что проблему решить вполне удалось. Я разделил игру на два процесса, один из которых опрашивает клавиатуру и сообщает о нажатии второму при помощи сигналов — USR1, USR2 и HUP, как раз три сигнала по трём управляющим клавишам — „←“, „→“ и «пробел». Последняя нужна, чтобы пускать шарик.
Решил сделать «Арканоид», не совсем классическую версию (на неё мне ещё бы пара вечеров потребовалась), но близкую. В игре есть три типа блоков разных цветов — вишнёвый разбивается сразу, синий при первом ударе превращается в вишнёвый, а от зелёного (самое интересное!) при ударе иногда отваливается часть, поймав которую, можно получить приятный бонус — более широкую ракетку, дополнительную жизнь или липкость. Последнее означает, что шарик в этом режиме не отскакивает от ракетки, а прилипает.

Ещё одна фишка игры — звуковое оформление, которое нечасто услышишь в консоли, я думаю. Правда, только для «Мака» (сделано командой «say», я заставляю её проговаривать буквы с большой скоростью), знаю, что для Линукса тоже есть команды для синтезатора речи («espeak», например), но мне негде их попробовать.
В игре пять жизней и пять уровней, кстати второй посвящён моей любимой жене, большой любительнице кошек (этот уровень как раз на скриншоте). Я сделал щадящую скорость полёта шарика, так что игру можно пройти даже без потерь, если хорошо потренироваться. Код, как водится, выложен на «Гитхаб».
От терминала, как и в шахматах, требуется уметь отображать 256 цветов и хорошая поддержка «Юникода». Нигде, кроме как под «Мак» игру я не тестировал,
Я записал небольшое видео игрового процесса. Я попробовал две программы для записи видео с экрана — «Скрини» и «КвикТайм», к сожалению обе нагружают процессор так, что игра начинает тормозить.
Видео выложил на «Яндекс.Видео». Добавлено позднее: сервис «Яндекс.Видео» прекратил своё существование.
Сетевая игра на bash: шахматы ★
Я давно хотел написать
Поскольку тонкости управления с клавиатурой съели очень много моего времени, я не стал заморачиваться с тонкостями совместимости, поэтому игра тестировалась только под Mac OS X, есть ненулевая вероятность, что она заработает и под Linux и уж точно её можно допилить там до рабочего состояния.
Для работы игра требует наличия nc (aka Netcat) и терминала с поддержкой 256 цветов (под Mac OS рекомендую iTerm2). При наличие интереса к игре, допилю до терминала на 16 цветов и /dev/tcp. Кстати начал выкладывать все свои
Эта игра запускается посложнее, так как сетевая, у неё два параметра, о которых она расскажет, если её запустить без них. Первый — адрес машины противника, второй — порт. Порт выбирается одинаковым на обеих машинах. Игру можно запустить и на одной машине, в двух консолях (на скриншоте как раз такой случай).
Играть просто — в каждый момент времени активна только одна доска (на скриншоте — правая, у неё буквы и цифры вокруг доски ярче), на активной доске курсор двигается курсорными клавишами — ←, →, ↑ и ↓, взять фигуру и поставить её на доску — по клавише пробела или Enter. Как только вы поставили фигуру на доску, ход переходит к сопернику. «Съесть» фигуру соперника проще простого — достаточно поставить свою фигуру на чужую. В игре есть защита — нельзя «съесть» свою фигуру.
Ничего помимо этого в игре нет — не производится правильность контроля ходов, нет проверки на завершение игры, можно даже ходить фигурами соперника. Было очень сложно придумать как обрабатывать нажатия в shell, так что остальное сделать я просто не успел, не поместилось в формат «игрушка за вечер».
#!/bin/bash
# Network chess by Evgeny Stepanischev //bolknote.ru 2011
if [ $# -ne 2 ]; then
echo Usage: $0 host-of-opponent port
exit
fi
# Хост оппонента
HOST="$1"
# Общий порт
PORT="$2"
# Клавиатурные комбинации извстной длины
SEQLEN=(1b5b4. [2-7]. [cd]... [89ab].{5} f.{7})
# Фигуры
WHITE=(♙ ♙ ♙ ♙ ♙ ♙ ♙ ♙ ♖ ♘ ♗ ♕ ♔ ♗ ♘ ♖)
BLACK=(♜ ♞ ♝ ♛ ♚ ♝ ♞ ♜ ♟ ♟ ♟ ♟ ♟ ♟ ♟ ♟)
# Наш ход?
OURMOVE=
# Я чёрный или белый?
MYCOLOR=
# Доска
declare -a XY
# Курсор
CX=1 CY=7
TAKEN=
# Необходимые нам клавиатурные коды
KUP=1b5b41
KDOWN=1b5b42
KLEFT=1b5b44
KRIGHT=1b5b43
KSPACE=20
# Восстановление экрана
function Restore {
echo -ne "\033[5B\033[5B\033[?25h\033[m"
stty "$ORIG" 2>/dev/null
(bind '"\r":accept-line' 2>/dev/null)
}
trap Restore EXIT
# Выключаем Enter
(bind -r '\r' 2>/dev/null)
# Выключаем остальную клавиатуру
ORIG=`stty -g`
stty -echo
# Убирам курсор
echo -e "\033[?25l"
# Отдаём события клавиатуры в сеть
function ToNet {
echo $1 | nc "$HOST" "$PORT"
}
# Реакция на клавиши курсора
function React {
case $1 in
$KLEFT)
if [ $CX -gt 1 ]; then
CX=$(($CX-1))
PrintBoard
fi
;;
$KRIGHT)
if [ $CX -lt 8 ]; then
CX=$(($CX+1))
PrintBoard
fi
;;
$KUP)
if [ $CY -gt 1 ]; then
CY=$(($CY-1))
PrintBoard
fi
;;
$KDOWN)
if [ $CY -lt 8 ]; then
CY=$(($CY+1))
PrintBoard
fi
esac
# Отдаём события клавиатуры в сеть
[ "$OURMOVE" ] && ToNet $1
}
# Проверка совпадения с известной клавиатурной комбинацией
function CheckCons {
local i
for i in ${SEQLEN[@]}; do
if [[ $1 =~ ^$i ]]; then
return 0
fi
done
return 1
}
# Функция реакции на клавиатуру, вызывает React на каждую нажатую клавишу,
# кроме KSPACE — на неё возвращается управление
function PressEvents {
local real code action
# Цикл обработки клавиш, здесь считываются коды клавиш,
# по паузам между нажатиями собираются комбинации и известные
# обрабатываются сразу
while true; do
# измеряем время выполнения команды read и смотрим код нажатой клавиши
# akw NR==1||NR==4 забирает только строку №1 (там время real) и №4 (код клавиши)
eval $( (time -p read -r -s -n1 ch; printf 'code %d\n' "'$ch") 2>&1 |
awk 'NR==1||NR==4 {print $1 "=" $2}' | tr '\r\n' ' ')
# read возвращает пусто для Enter и пробела, присваиваем им код 20,
# а так же возвращаются отрицательные коды для UTF8
if [ "$code" = 0 ]; then
code=20
else
[ $code -lt 0 ] && code=$((256+$code))
code=$(printf '%02x' $code)
fi
if [ $code = $KSPACE ]; then
[ "$OURMOVE" ] && ToNet $KSPACE
SpaceEvent && return
continue
fi
# Если клавиши идут подряд (задержки по времени нет)
if [ $real = 0.00 ]; then
seq="$seq$code"
if CheckCons $seq; then
React $seq
seq=
fi
# Клавиши идут с задержкой (пользователь не может печатать с нулевой задержкой),
# значит последовательность собрана, надо начинать новую
else
[ "$seq" ] && React $seq
seq=$code
# возможно последовательность состоит из одного символа
if CheckCons $seq; then
React $seq
seq=
fi
fi
done
}
# Проверяем чёрная или белая фигура
function CheckColor {
echo -n ${1:0:1}
}
# Первичное заполнение доски
function FillBoard {
local x y ch
for y in {1..8}; do
for x in {1..8}; do
ch='S '
if [ $y -le 2 ]; then
ch=B${BLACK[$x+8*$y-9]}
else
if [ $y -ge 7 ]; then
ch=W${WHITE[$x+8*$y-57]}
fi
fi
XY[$x+100*$y]=$ch
done
done
}
# Вывод букв по краю доски
function PrintBoardLetters {
local letters=abcdefgh
[ -z "$OURMOVE" ] && echo -ne "\033[30m" || echo -ne "\033[0m"
echo -n ' '
for x in {0..7}; do
echo -n "${letters:$x:1} "
done
echo
}
# Вывод цифры по краю доски
function PrintBoardDigit {
[ -z "$OURMOVE" ] && echo -ne "\033[30m"
echo -en " $((9-$1))\033[0m "
}
# Вывод доски
function PrintBoard {
local x y c ch
local colors=('48;5;209;37;1' '48;5;94;37;1')
PrintBoardLetters
for y in {1..8}; do
PrintBoardDigit $y
for x in {1..8}; do
c=${colors[($x+$y) & 1]}
ch=${XY[$x+100*$y]}
if [[ $CX == $x && $CY == $y ]]; then
c="$c;7"
[ "$TAKEN" ] && ch=$TAKEN
[ $MYCOLOR == B ] && c="$c;38;5;16"
fi
[[ $(CheckColor "$ch") == "B" ]] && c="$c;38;5;16"
echo -en "\033[${c}m${ch:1:1} \033[m"
done
PrintBoardDigit $y
echo
done
PrintBoardLetters
echo -e "\033[11A"
}
# Приём событий
function NetListen {
nc -l $PORT
}
# Готовы слушать события сети
function NetEvents {
local code
while true; do
code=$(NetListen)
[[ "$code" == "$KSPACE" ]] && SpaceEvent && return
React $code
done
}
# Реакция на нажатие Space и Enter — взять или положить фигуру
function SpaceEvent {
local xy
# Проверяем, есть ли фигура под курсором
let xy="$CX+$CY*100"
# Фигуры нет
if [ "${XY[$xy]:-S }" = "S " ]; then
if [ -z "$TAKEN" ]; then
echo -en "\007"
else
# Положили фигуру
XY[$xy]=$TAKEN
TAKEN=
return 0
fi
# Фигура есть
else
# Мы не должны позволять «съесть» свою фигуру
if [[ $(CheckColor "$TAKEN") == $(CheckColor "${XY[$xy]}") ]]; then
echo -en "\007"
else
# Фигура есть «в руке», мы «съедаем» противника
if [ "$TAKEN" ]; then
XY[$xy]=$TAKEN
TAKEN=
return 0
else
# «В руке» ничего не было, мы взяли фигуру
TAKEN=${XY[$xy]}
XY[$xy]="S "
fi
fi
fi
return 1
}
# Очистка клавиатурного буфера
function ClearKeyboardBuffer {
# Быстро — через zsh
which zsh &>/dev/null && zsh -c 'while {} {read -rstk1 || break}' && return
# Медленно — через bash
local delta
while true; do
delta=`(time -p read -rs -n1 -t1) 2>&1 | awk 'NR==1{print $2}'`
[[ "$delta" == "0.00" ]] || break
done
}
FillBoard
# Кто будет ходить первым
ToNet HI
[[ "$(NetListen)" == "HI" ]] && OURMOVE=1
sleep 0.2
ToNet ULOOSE
[ "$OURMOVE" ] && MYCOLOR=W || MYCOLOR=B
PrintBoard
# Основной цикл — обрабатываем события из сети или с клавиатуры
while true; do
if [ -n "$OURMOVE" ]; then
ClearKeyboardBuffer
PressEvents
OURMOVE=
else
NetEvents
OURMOVE=1
fi
PrintBoard
done
Bashnut Battery
Есть такая программа — coconutBattery, красиво показывает под MacOS X состояние батареи и некоторые другие характеристики. Поскольку я тут тренируюсь писать под Bash, решил сегодня повторить её функционал. Полностью не получилось, так как новая версия MacOS X выдаёт

В этом скрипте я разучил несколько новых фокусов, рад что сел за эту задачу. И ещё новинка — я теперь проверяю тип терминала, если он содержит «256» (поддерживаются 256 цветов), то цвета берутся из расширенной палитры. Сам код — далее.
#!/bin/bash
# Хост для информации о серийнике
HOST='www.chipmunk.nl'
# Выбираем информацию о батарее, получится что-то вроде
# Amperage 18446744073709550574 Flags 4 Capacity 6632 Current 6338 Voltage 8192 CycleCount 14 и тд
BATTERY=( $(\
ioreg -w0 -l |
egrep '(Max|Design)Capacity|(Legacy|IO)BatteryInfo|product-name|Temperature|PlatformSerialNumber' |
tee >(awk -F{ '/(Legacy|IO)BatteryInfo/ { gsub(/ |\}|"/, ""); gsub(/,|=/, " "); print $2 }') |
tee >(awk -F'"' '/(Max|Design)Capacity|product-name|Temperature|PlatformSerialNumber/ { gsub(/[=<>-]/, ""); print $2 $3 $4}') |
grep -vF '"' |
tr '\n' ' '
))
# Достаём значение по ключу из BATTERY
function GetBatVal {
local i
for ((i=0; i<${#BATTERY[@]}; i+=2)); do
if [ $1 = ${BATTERY[$i]} ]; then
echo ${BATTERY[$i+1]}
break
fi
done
}
# Получаем информацию о неделе выпуска
function GetPlatform {
local tmpfile="$TMPDIR/battery-age-mac"
# Файл с кешем, чтобы не дёргать сервис каждый раз
if [ -e $tmpfile ]; then
# проверим время создания файла
eval $(stat -s $tmpfile)
# Если кеш устарел, то удаляем его
if [ $((`date +%s` - $st_mtime)) -gt 86400 ]; then
rm -f $tmpfile
else
cat $tmpfile
return
fi
fi
local date=($(\
curl --connect-timeout 3 "http://$HOST/cgi-fast/applemodel.cgi?serienummer=$1" 2>/dev/null |
sed 's/<BR>/`/g' | awk 'BEGIN {RS="`"} /Production (year|week)/{gsub("<[^>]+>", ""); print $2 $3}' |
sort | cut -d: -f2 | tr "\r\n" ' '
))
if [ ${#date[@]} -le 1 ]; then
echo NA
return
fi
local scale
local diff
# Считаем количество недель
let diff="($(date +%Y)-${date[1]})*52177 + ( $(date +%V) - ${date[0]}) * 1000"
# Выбираем что будем отображать — недели, месяцы, годы
if [ $diff -gt 5 ]; then
diff=$(( $diff / 4340 ))
scale=Month
if [ $diff -gt 12 ]; then
diff=$(( $diff / 12 ))
scale=Year
fi
else
diff=$(( $diff / 1000 ))
scale=Week
fi
[ $diff -gt 1 ] && scale=${scale}s
echo $diff $scale | tee $tmpfile
}
# Рисуем прогрессбар
function PrintBat {
# Если терминал поддерживает 256 цветов, покажем красиво
if [[ $TERM =~ 256 ]]; then
local colors=("38;5;160" "38;5;220" "38;5;34")
else
# Иначе, увы, цвета попроще
local colors=(31 33 32)
fi
local c=${colors[0]}
[ $1 -ge 13 ] && c=${colors[1]}
[ $1 -ge 20 ] && c=${colors[2]}
local bar=$(cat)
local prg=$(printf "%0$1s" | tr 0 ${bar:2:1})
local rep="\033[${c}m$prg\033[30m"
echo -e ${bar/$prg/$rep}
}
# Возраст Мака
age=$(GetPlatform `GetBatVal IOPlatformSerialNumber`)
# Всё достаточно очевидно: боксы с информацией
cur=$(GetBatVal Current)
max=$(GetBatVal Capacity)
let percent="($cur*40/$max)"
echo -e '\033[1m\n Bashnut Battery by Evgeny Stepanischev\033[0m'
echo
echo ' Battery charge'
echo ┌──────────────────────────────────────────┐
printf '│ Current charge: % 5d mAh │\n' $cur
printf '│ Maximum charge: % 5d mAh │\n' $max
echo '│ │'
echo -e '│ ████████████████████████████████████████ \033[0m│' | PrintBat $percent
echo └──────────────────────────────────────────┘
des=$(GetBatVal DesignCapacity)
max=$(GetBatVal MaxCapacity)
let percent="($max*40/$des)"
echo ' Battery capacity'
echo ┌──────────────────────────────────────────┐
printf '│ Current capacity: % 5d mAh │\n' $max
printf '│ Design capacity: % 5d mAh │\n' $des
echo '│ │'
echo -e '│ ████████████████████████████████████████ \033[0m│' | PrintBat $percent
echo └──────────────────────────────────────────┘
echo ' Details'
echo ┌──────────────────────────────────────────┐
printf '│ Mac model: % 17s │\n' $(GetBatVal productname)
printf '│ Age of your Mac: % 17s |\n' "$age"
printf '│ Battery loadcycles: % 5d │\n' $(GetBatVal CycleCount)
printf '│ Battery temperature: % 5s˚С |\n' `echo "scale=1;($(GetBatVal Temperature)+5)/100" | bc`
echo └──────────────────────────────────────────┘
echo -e "\033[0m"