AppleScript — встроенный в Mac OS X язык сценариев. С момента появления в 1990 году в операционных системах System, AppleScript превратился в мощный инструмент, позволяющий управлять операционной системой, приложениями и объектами системы. AppleScript имеет, как говорят, «юзер-френли» синтаксис. Поэтому любой мало-мальски разбирающийся в английском языке пользователь (умеющий читать и создавать алгоритмы), может с лёгкостью понять и освоить этот скриптовый язык. Сам процесс «программирования» на AppleScript больше похож на монолог с ситемой на английском, чем на программирование. Тем не менее, AppleScript относят к объекто-ориентированным языкам, и с помощью AppleScript Studio входящего в пакет для разработчиков Xcode, на нём можно создавать даже целые программы. Для нас же AppleScript интересен в первую очередь как средство эффективной автоматизации различных рутинных и повторяющихся действий, и при этом не обременяет изучением сложных языков программирования. Конечно, bash (shell) скрипты являются более гибким средством, но когда речь заходит о GUI (графическом пользовательском интерфейсе), то bash нам ни как не друг, в отличии от AppleScript, который позволяет создавать сценарии способные взаимодействовать с системой и пользователем через графический интерфейс. К тому же в AppleScript можно легко внедрять элементы «консоли», то есть выполнять «терминальные» команды внутри AppleScript. Но об этом чуть позже.

Весь процесс создания рабочего скрипта происходит или в Xcode, или в приложении Редактор AppleScript. Последний находится в папке Программы > Утилиты, с ним мы и будем работать. В AppleScript для меня самое интересное и ценное то, что рабочий скрипт можно сохранить в виде программы, а затем поделиться ею с другими «маководами» и использовать её на других компьютерах Mac. Ну что ж, запустим Редактор AppleScript и посмотрим на его рабочее пространство:Окно редактора AppleScriptСам Редактор AppleScript выглядит довольно просто и лаконично: ничего лишнего. Из распоряжения имеются такие кнопки:

  • Запись — позволяет записывать происходящее в системе. Если вы обладаете абсолютно нулевыми навыками в скриптовом программировании, нажмите эту кнопку, создайте на Рабочем столе (к примеру) папку. Затем остановите запись. В окне редактора появится код ваших действий. Если теперь этот код сохранить как программу и запустить, то выполниться точно такое же действие. Это очень удобно использовать для самообучения, особенно когда не ясно как реализовать ту или иную функцию.
  • Остановить — кнопка для остановки записи сценария.
  • Запустить — выполняет запуск скрипта
  • Компилировать — выполняет проверку кода и при ошибке сообщает об этом. К тому же её нажатие как бы «включает» подсветку синтаксиса, что весьма удобно и наглядно разделяет код. В общем-то эту кнопку можно обозвать кнопкой Отладка.

Как я уже писал ранее, AppleScript очень простой к пониманию язык, поэтому ещё одно «описание по учебнику» — это скучное занятие. Давайте лучше сразу перейдём к примерам? Это первый пример кода:

-- это комментарий в одну строку
-- он выделяется двумя дефисами

(* это тоже комментарий, но его можно
использовать в несколько строк *)

Такими вставками я буду комментировать происходящее в скрипте. Комментарии, как вы поняли, не воспринимаются как код и при компиляции/исполнении игнорируются, а для нас это очень удобный вариант не заблудиться в строках кода. Теперь рассморим пример «скрытного» или «фонового» выполнения какого-либо действия, например заставим AppleScript говорить :) Вставьте в Редактор AppleScript данную строчку:

say "Hello. I'm AppleScript." using "Vicki"

А теперь нажмите кнопку «Запустить». То есть в данном примере выполняется действие в фоновом режиме и при этом сценарий ни как не взаимодействует с пользователем. Что интересно, аналогичную команду можно выполнить через Терминал:

say -v Vicki "Hello. I'm AppleScript."

А теперь ещё вот такой финт. Вставляем данную строку в редактор AppleScript:

do shell script "say -v Vicki \"Hello. I'm AppleScript.\""

И снова нажимаем «Запустить». Происходит аналогичное двум первым действие, но данный пример наглядно показывает как в AppleScript можно интегрировать терминальные команды (обратите внимание, что в констркукции из кавычек я использовал экранированные обратным слешем других кавычек, пренадлежащих не AppleScript, а bash: "\"\"" - это необходимое условие иначе будет ошибка). Данная возможность нам ещё не раз пригодиться. Теперь давайте разберём пример взаимодействия AppleScript с пользователем. Вставляем в редактор такой код:

tell application "Finder" to display dialog ¬
	"А это просто тестовое сообщение ;)" with icon 1 ¬
	with title "Я заголовок окна" buttons {"Ну ОК"} default button 1 cancel button 1

Ну и запускаем его. Ну как? Теперь разберём по косточкам этот кусок «яблочного» кода:

  • tell application «Finder» to — сказать «Файндеру» что… (вместо Finder может выступать любое приложение, например тот же Twitter, главное чтоб это приложение присутствовало в системе);
  • display dialog «текст»- показать диалоговое окно с текстом что находится в кавычках, а далее опционально:
    • with icon X — иконка окна, где X — идентификатор иконки: 1 — иконка приложения, 2 — иконка «Внимание» и так далее (цифрами можно подбирать иконки);
    • with title «заголовок окна» — текст заголовка окна;
    • buttons {«Кнопка_1″,»Кнопка_2″,…,»Кнопка_N»} — кнопки диалогового окна;
    • default button X — кнопка выбранная по-умолчанию, где X — номер кнопки по-порядку;
    • cancel button X — кнопка оповещающая сценарий о завершении работы (Отмена).

Теперь свяжем диалоговое окно с каким либо действием:

tell application "Finder" to display dialog ¬
	"Привет, я Vicki и я умею говорить. Хочешь послушать?" with icon 1 ¬
	with title "Vicki приветствует!" buttons {"Хочу", "Неа"} ¬
	default button 1 cancel button 2
if button returned of result = "Хочу" then
	say "Hello. I'm Vicki and I like MacDaily." using "Vicki"
end if

Тут уже появилась классическая конструкция ifend if. Собственно, последнюю конструкцию:

if button returned of result = "Хочу" then
	say "Hello. I'm Vicki and I like MacDaily." using "Vicki"
end if

Можно интерпретировать как: если была нажата кнопка «Хочу» нужно выполнить действие лежащее в конструкции if тут_действие_или_несколько_действий end if. Конструкции ifend if могут быть и более сложные, например:

tell application "Finder" to display dialog ¬
	"Привет, я Vicki и я умею говорить. Хочешь послушать?" with icon 1 ¬
	with title "Vicki приветствует!" buttons {"Хочу", "Неа"} ¬
	default button 1
if button returned of result = "Хочу" then
	say "Hello. I'm Vicki and I like MacDaily." using "Vicki"
else
	say "Nu ee ne nado..." using "Vicki"
end if

Ну это всё баловство :) Давайте разберём что-то более серьёзное? — А давайте! Как то ранее я сделал мини-программулину на bash, которая позволяла включить или выключить отображение скрытых папок и файлов. Работает она и по сей день отлично и со своей задачей справляется на все 100%, но так как она создана на основе bash-скрипта, то ни о каком пользовательском интерфейсе не может быть и речи, работает всё «на мышу». Сегодня я хочу исправиться и представить новую её интерпритацию, на этот раз на AppleScript. Совместим приятное с полезным (теорию с практикой):

on run -- при запуске приложения через двойной клик

try
	(* Используем знакомую терминальную команду для присвоения переменной 
	visiblesate текущее положение дел с отображением скрытых файлов и папок.
	То есть данная команда должна присвоить переменной visiblesate значение
	FALSE или TRUE *)
	set visiblesate to do shell script "defaults read com.apple.finder AppleShowAllFiles"
on error -- при ошибке...
	(* Часто по-умолчанию параметр AppleShowAllFiles в com.apple.finder.plist
	вообще отсутствует, что равносильно значению FALSE - то есть файлы и папки
	скрыты. Но при отсутствии данного ключа будет выдаваться ошибка и работа
	скрипта будет нарушена. Чтоб этого не происходило мы указали параметр
	on error - то есть при ошибке…принудительно присвоить переменной 
	visiblesate значение FALSE *)
	set visiblesate to "FALSE"
end try

if visiblesate = "FALSE" then -- если файлы скрыты, то...
	-- говорим "Файндеру показать окно с такими-то кнопками и таким-то текстом"
	tell application "Finder" to display dialog ¬
	"В данный момент все системные файлы и папки скрыты. Показать их?" with icon 1 ¬
	with title "Показать?" buttons {"Показать", "Отмена"} default button 1 cancel button 2
	-- если будет нажата кнопка "Показать", то выполняем две команды:
	if button returned of result = "Показать" then
	-- вносим значение TRUE в com.apple.finder.plist
		do shell script "defaults write com.apple.finder AppleShowAllFiles TRUE"
		-- перезагружаем Finder чтоб изменения всупили в силу
		do shell script "killall Finder"
	end if -- завершаем процедуру

-- если же файлы отображаются, то...
else if visiblesate = "TRUE" then
	-- говорим "Файндеру показать окно с такими-то кнопками и таким-то текстом"
	tell application "Finder" to display dialog ¬
	"В данный момент все системные файлы и папки отображаются. Скрыть их?" with icon 1 ¬
	with title "Скрыть?" buttons {"Скрыть", "Отмена"} default button 1 cancel button 2
	-- если будет нажата кнопка "Скрыть", то выполняем две команды:
	if button returned of result = "Скрыть" then
		-- вносим значение FALSE в com.apple.finder.plist
		do shell script "defaults write com.apple.finder AppleShowAllFiles FALSE"
		-- перезагружаем Finder чтоб изменения всупили в силу
		do shell script "killall Finder"
	end if
end if -- завершаем процедуру

end run -- конец работы

Теперь нажмём кнопку «Запустить» в Редакторе AppleScript чтоб убедиться, что мы не допустили ошибок, ну и чтоб проверить работоспособность сценария. Если всё ОК, то в Редакторе AppleScript нажимаем Файл > Экспортировать… и выбираем Формат файла: программа, сохраняем на Рабочий стол. Всё! Мы получили готовую программку для скрытия и отображения скрытых/системных файлов и папок. Удобно же? Это приложение потом можно привести в «человеческий вид»: изменить иконку, добавить копирайты в файл Info.plist, но это уже тема для отдельной заметки. В общем-то это примитивный такой сценарий, но он хорошо и наглядно показывает возможности AppleScript.

Если данная тема вам интересна — оставляйте комментарии. В следующих заметках я буду приводить другие интересные и полезные примеры.


Метки:
 
Понравилось? Поделись с друзьями!
  • Я когда-то писал эмулятор Brainfuck на AppleScript: http://bolknote.ru/2011/07/01/~3307/.

  • В Горном Льве вместо TRUE и FALSE стоит использовать YES и NO, в противном случае shell-скрипт будет постоянно глючить / не отрабатывать.

    • А вы попробуйте ;) Я же не с потолка писал :) И вообще обычно Mac OS X интерпреирует значения YES = TRUE = 1 = bool TRUE, и NO = FALSE = 0 = bool FALSE. Так что, в принципе, без разницы какое значение использовать, но «Горный Лев» «предпочитает» значение или «стринговое» TRUE/FALSE:

      <key>Ключ</key>
      <string>TRUE</string>
      <key>Ключ</key>
      <string>FALSE</string>
      

      или «булейное» TRUE/FALSE:

      <key>Ключ</key>
      <true />
      <key>Ключ</key>
      <false />
      

      Casing    Марина Власик

  • Пробую создать скрипт для подключения к устройствам через usb to serial адаптер,
    подскажите как обрабатывать сообщения терминала?

    tell application "Terminal" to display dialog ¬
    	"Подключите кабель USB to Serial" with icon 1 ¬
    	with title "Ожидание подключения..." buttons {"OK", "Cancel"} ¬
    	default button 1 cancel button 2
    if button returned of result = "OK" then
    	activate
    	do shell script "screen /dev/cu.usbserial"
    	if ¬
    	"Cannot exec '/dev/cu.usbserial': No such file or directory" ¬ 
    	then display dialog ¬
    	"Ошибка: Устройство не найдено. Подключите кабель и попытайтесь снова" ¬ 
    	with icon 1 with title "Ожидание подключения..." buttons {"OK"} ¬
    	default button 1
    	if button returned of result = "OK" then
    	do shell script "unmount /dev/cu.usbserial"
    	quit application "Terminal"
    	end if
    end if 
    

    Нужно чтобы когда терминал возвращает ошибку «Cannot exec ‘/dev/cu.usbserial’: No such file or directory» then display dialog» выводило диалог, что устройство не найдена и по кнопке OK закрывало окно терминала.
    Вопрос: Какого открывается 4 окна терминала? Где то я напортачил с вызовами его
    как обработать возвращаемые ошибки терминала?

  • Ахахах!
    Разобрался!
    Выкладываю мож кому то пригодится:

    tell application "iTerm" to display dialog ¬
       "Подключите кабель USB to Serial" with icon 1 ¬
       with title "Ожидание подключения..." buttons {"OK", "Cancel"} ¬
       default button 1 cancel button 2
    if button returned of result = "OK" then
       set errText to "Cannot exec '/dev/cu.usbserial': No such file or directory"
       tell application "iTerm"
       activate
       try
       do shell script "screen /dev/cu.usbserial"
       on error errText
       display dialog ¬
       "Устройство не найдено. Подключите его и попытайтесь снова." with icon 1 ¬
       with title "Ожидание подключения..." buttons {"OK"} ¬
       default button 1
       if button returned of result = "OK" then
       #do shell script "unmount /dev/cu.usbserial"
    	quit i term application "iTerm"
    	end if
    	end try
    	end tell
    end if
    
    • Не успел проверить и отписаться :) Рад что сам во всём разобрался ;) Пример интересный и полезный, думаю найдутся «маководы» которым пригодится данное решение. Спасибо!
      Casing    Sergey

  • помогите, очень нужно написать простой скрипт при запуске которого стирается корзина.

    tell application «Finder»
    empty trash
    end tell

    Не справляется с задачей требует подверждения задания доп меню, нужно когда запускает прогу чтобы все стирал безоговорочно.

  • http://1-pack.ru/trash.png

    Уж как только не делал.

  • пошел на хитрость но уперся в новую проблему

    tell application «Terminal»
    do script «sudo rm -rf ~/.Trash/*
    PASWW
    »
    end tell

    где pasww — пароль админа, но теперь заметил что удаляет только файлы главного диска и сторонние диски не чистит. Что делать посоветуйте

  • Я когда то написал программу под OS X: ARO App store мой магазин он качает с сайта ARO.Store.OS.X.Apple.com это хостинг на котором залиты программы мои.Он не работает (сайт) это всего лишь чистый хостинг без движка.

  • Спасибо! Ура, я сделал команду автоматического удаления кеш папок!

  • поставил пароль на прошивку через терминал.
    В утилитах были строки, не знаю как они называются…
    взял слово — ****** LOG в начале строки, а потом забыл что за слово вместо ******..
    Рядом нету макбука, не могу повторить на другом компе просмотреть эти записи чтобы вспомнить..