Как закрыть окно из приложения, передав имя файла?

Как закрыть окно из приложения, передав имя файла?

Я пытаюсь создать команду оболочки на основе AppleScript, которая прикажет приложению Preview из Mac OS X закрыть определенное окно.

#!/bin/sh

osascript <<EOF
tell application "Preview"
   close "$1"
end tell
EOF

Но это не работает: я получаю сообщение об ошибке

25:52: execution error: Preview got an error: "musixdoc.pdf" doesn’t understand the close message. (-1708)

Сопутствующий вопрос:Как закрыть приложение OS X из командной строки, используя псевдоним, определенный в моем .bash_profile?

решение1

Заставляем Preview.app принимать команды AppleScript

По умолчанию AppleScripting Preview не будет работать, поскольку Preview не хватает необходимого словаря. Чтобы исправить это, проверьтеОтвет Лаури здесь, который объясняет настройку NSAppleScriptEnabledPreview.app.

Закройте Preview.app, затем откройте терминал и введите:

sudo defaults write /Applications/Preview.app/Contents/Info NSAppleScriptEnabled -bool true
sudo chmod 644 /Applications/Preview.app/Contents/Info.plist
sudo codesign -f -s - /Applications/Preview.app


Закрытие окна из приложения

1) По индексу окна или названию окна

Команда для закрытия окна любого именованного приложения будет выглядеть примерно так:

tell application "Preview" to close window 1

… или если вы хотите закрыть именованное окно документа, например foo.jpg:

сказать приложению "Предварительный просмотр" закрыть (каждое окно с именем "фу.jpg")

Итак, в вашем скрипте оболочки это будет выглядеть так:

#!/bin/sh
osascript <<EOF
tell application "Preview"
  close (every window whose name is "$1")
end tell
EOF

Здесь первый аргумент, передаваемый скрипту, — это имя окна, которое вы хотите закрыть, например ./quit.sh foo.jpg. Обратите внимание, что если ваш файл содержит пробелы, вам необходимо заключить имя файла в кавычки, например ./quit.sh "foo bar.jpg".

Или, если вы хотите закрыть произвольные окна любого приложения, используйте это:

#!/bin/sh
osascript <<EOF
tell application "$1"
  close (every window whose name is "$2")
end tell
EOF

Здесь вы могли бы использовать, ./quit.sh Preview foo.jpgнапример.

2) По имени файла

Если вы хотите закрыть окно, которое принадлежит определенному документу, но при этом указываете имя файла, вам нужно что-то еще. Это потому, что многостраничный PDF может отображаться как foo.pdf (Page 1 of 42), но вы просто хотите передать foo.pdfего AppleScript.

Здесь мы перебираем окна и сравниваем имена файлов с аргументом, переданным скрипту:

osascript <<EOF
tell application "Preview"
    set windowCount to number of windows
    repeat with x from 1 to windowCount
        set docName to (name of document of window x)
        if (docName is equal to "$1") then
            close window x
        end if
    end repeat
end tell
EOF

Теперь вы можете просто вызвать ./quit.sh foo.pdf. В общем случае для всех приложений с именованными окнами документов это будет выглядеть так:

osascript <<EOF
tell application "$1"
    set windowCount to number of windows
    repeat with x from 1 to windowCount
        set docName to (name of document of window x)
        if (docName is equal to "$2") then
            close window x
        end if
    end repeat
end tell
EOF


Предупреждение: автоматическое закрытие Preview.app

Preview.app — одно из таких приложений, которое автоматически завершает работу после закрытия последнего окна документа. Это делается для экономии памяти и «очистки». Чтобы отключить это поведение, выполните следующее:

defaults write -g NSDisableAutomaticTermination -bool TRUE

Конечно, чтобы отменить это, измените TRUEна FALSE.


Использование функций вместо скриптов

Наконец, я бы предложил поместить ваши скрипты в функцию, которая всегда доступна в вашей оболочке. Чтобы сделать это, добавьте скрипты в ваш ~/.bash_profile. Создайте этот файл, если он не существует.

cw() {
osascript <<EOF
tell application "$1"
    set windowCount to number of windows
    repeat with x from 1 to windowCount
        set docName to (name of document of window x)
        if (docName is equal to "$2") then
            close window x
        end if
    end repeat
end tell
EOF
}

После сохранения профиля bash и перезапуска оболочки вы сможете совершать вызовы cw Preview foo.pdfоткуда угодно.

решение2

Ответ slhck выглядит хорошим и исчерпывающим.Осторожно, выполнение третьей строки кода:

sudo codesign -f -s - /Applications/Preview.app

«похоже», что это приводило к сбою Preview при каждом запуске из-за следующего:

Application Specific Information:
XPC domain creation failed: The code signature is not valid: The operation couldn’t be completed. (OSStatus error -67061.)

Согласно руководству по кодированию, это -fозначает принудительное «заменение существующей подписи кодовым знаком» и -s«подписание кода по указанному пути»… в данном случае-

Судя по всему, Preview теперь неправильно подписан и непригоден для использования. :(

Связанный контент