Archive for the 'shell script' Category

2017/09/19 Notesで選択中のnoteやfolderの情報を取得する?

defaultsコマンド経由でNotes.app(日本語ローカライズ名:メモ.app)で選択中のnoteやfolderの情報を取得する(参考になるかもしれない)AppleScriptです。

selectionとかselected folderなどの用語が用意されていないことでおなじみのNotes.app。「現在表示中のノート」を処理したいのはやまやまですが、用語辞書に書かれていない機能は、まっとうな手段では呼び出せません。

となると、「まっとうでない方法」を検討することになります。

まっとうでない手段を選ぶことで、スピード低下、安定性のなさ、メンテナンスの手間など負の側面と向き合う必要が出てきますが、問題自体の解決は行えます。

(1)GUI Scripting
まっとうでない方法の筆頭。画面上から無理やり情報を取得して、選択状態にあるGUI部品のタイトルを取得することで、選択中のノートの情報を特定できそうです。興味と必要性がないので深追いしていませんが、Notes.appの各種表示状態(アカウント情報一覧を表示するとか、表示を隠すとか)に合わせて数パターンの処理を用意しておくことで、実現できるメドは立っています。

ただし、GUI Scriptingのつねとして、「スピードは通常のAppleScriptの100倍以上遅い」(Cocoa経由の処理と比較すると数万倍遅い)「予期しないアプリケーション側の表示には追従できない」「OSやアプリケーションのバージョンアップにともない、表示内容やGUI部品の階層が変わったぐらいで書き換えが必要になる」ということから、多用は避けたいところです。

(2)defaultsコマンド
まっとうでない方法として有名。アプリケーションの設定情報を直接読んで処理します。アプリケーションやOSがバージョンアップして内部情報が変更されると動かなくなるのはGUI Scripting同様。

defaultsコマンドから得られる情報をAppleScriptネイティブのデータ形式(recordとか)に変換するのが面倒でしたが、Cocoaの機能を利用して割と手軽に読み込めるようになってきました。

Terminal上で、

  defaults read com.apple.Notes

を実行してみたところ、設定情報の中に現在選択中のnoteおよびfolderを記録している箇所があったので、実際にAppleScript中に記述して取り出してみました。

今回掲載したのが、そのdefaultsコマンドを利用した情報取得のサンプルです。このデータをもとにSQLiteのデータベースを検索してみればいいかも、などと思ってデータベースを漁ってみたものの、

notes_sqlite3_resized.png

defaultsから得られたような形式のID(UUIDっぽい?)はDB中に記録されていないようで、ちょっと残念です(SQLiteではなくCoreData経由で調べるべき?)。もう少し調べてみると手がかりが見つかるかもしれませんが、出先の電車の中で調べた程度だったのでこのぐらいです。

AppleScript名:Notesで選択中のnoteやfolderの情報をdefaults経由で取得する
– Created 2016-10-31 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4827

set sRes to do shell script ” defaults read com.apple.Notes ArchivedUIState”
set aDict to deserializeToPlistString(sRes) of me

set curNote to (aDict’s valueForKey:“currentNote”) as string
–>  ”860327F4-4E6F-44FB-92EC-720B47CDD38A”

set curNoteFol to (aDict’s valueForKey:“currentNoteFolder”) as string
–>  ”184daff620aca4ad23fd2bf70d0b76af”

set folderListHidden to (aDict’s valueForKey:“folderListHidden”) as integer as boolean
–>  false

return {curNote, curNoteFol, folderListHidden}

–XML-format plist string–> list or record
on deserializeToPlistString(aStr as string)
  set deStr to current application’s NSString’s stringWithString:aStr
  
set theData to deStr’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aList to current application’s NSPropertyListSerialization’s propertyListWithData:theData options:(current application’s NSPropertyListMutableContainersAndLeaves) |format|:(missing value) |error|:(missing value)
  
return aList
end deserializeToPlistString

★Click Here to Open This Script 

2017/07/21 指定のPNG画像をASCII ART化してTextEditでオープン v2

jp2aを利用して指定のPNG画像を色付きHTML形式のアスキーアート化して出力し、HTMLをRTFに変換してTextEditでオープンしてフォントを変更するAppleScriptです。

指定のJPEG画像をアスキーアート化するjp2aは、Homebrew経由でインストールしてください。

asciiart4_resized.png

asciiart3_resized.png
▲このように縦長で余白の多い画像から、自動で余白部分をトリミングして処理

asciiart_z.png
▲左側はPNG画像の余白トリミング処理を行ったもの、右側はトリミング処理を行わなかったもの

アスキーアート化するにあたって、元画像の余白部分をトリミングできたほうが良好な結果が得られるため、処理対象をJPEG画像からPNG画像(背景透過)に変更し、以前に使った画像余白トリミングフレームワーク「KGPixelBoundsClipKit」を用いてトリミングしてJPEG画像に変換。

トリミングしたJPEG画像をjp2aでHTMLのアスキーアートに変換し、さらにHTMLをスタイル付きテキスト(NSAttributedString)に変換。

スタイル付きテキストをRTF(リッチテキストフォーマット)に変換してファイル出力。RTFになればTextEditで扱えるので、TextEditでオープンして本文のフォントを等幅フォント(Osaka-mono)に指定してウィンドウのサイズを変更しています。

テストする際には、KGPixelBoundsClipKitフレームワークのバイナリを~/Library/Frameworksフォルダに入れてお試しください。

–> Download Framework Binary

AppleScript名:指定のPNG画像をASCII ART化してTextEditでオープン v2
– Created 2017-07-21 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
use framework “KGPixelBoundsClipKit” –https://github.com/kgn/KGPixelBoundsClip
–http://piyocast.com/as/archives/4736

set aFile to choose file of type {“public.png”}

–PNG画像の余白をトリミング
set anImage to (current application’s NSImage’s alloc()’s initWithContentsOfFile:(POSIX path of aFile))
set bImage to anImage’s imageClippedToPixelBounds()

–トリミング結果をデスクトップにJPEG形式で保存
set aDesktopPath to (current application’s NSProcessInfo’s processInfo()’s environment()’s objectForKey:(“HOME”))’s stringByAppendingString:“/Desktop/”
set savePath to aDesktopPath’s stringByAppendingString:((current application’s NSUUID’s UUID()’s UUIDString())’s stringByAppendingString:“.jpg”)
set fRes to saveNSImageAtPathAsJPG(bImage, savePath, 100) of me

–ASCII ARTに変換してHTMLとして出力
set anAlias to (POSIX file (savePath as string)) as alias
set htmlRes to jpegToAsciiArt(anAlias, 120) of me

–出力されたHTMLデータを評価してスタイル付きテキストに変換
set htmlData to current application’s NSString’s stringWithString:htmlRes
set keyList to {current application’s NSDocumentTypeDocumentAttribute, current application’s NSCharacterEncodingDocumentAttribute}
set valList to {current application’s NSHTMLTextDocumentType, current application’s NSUTF8StringEncoding}
set optDict to current application’s NSMutableDictionary’s dictionaryWithObjects:valList forKeys:keyList
set aStyledStr to current application’s NSAttributedString’s alloc()’s initWithData:(htmlData’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)) options:optDict documentAttributes:(missing value) |error|:(missing value)

–スタイル付きテキストをRTFとしてデスクトップに保存
set targFol to POSIX path of (path to desktop)
set aUUID to current application’s NSUUID’s UUID()’s UUIDString() as text
set bRes to my saveStyledTextAsRTF(aUUID, targFol, aStyledStr) –PDFで書き出す
set newPath to targFol & aUUID & “.rtf”

–保存したRTFをTextEditでオープンして等幅フォント設定して、Window横幅を変更
tell application “TextEdit”
  activate
  
open (POSIX file newPath) as alias
  
  
tell text of document 1
    set font of every attribute run to “Osaka-Mono”
  end tell
  
  
tell window 1
    set {x1, y1, x2, y2} to bounds
    
set bounds to {x1, y1, (x1 + 800), y2}
  end tell
end tell

–NSImageを指定パスにJPEG形式で保存
on saveNSImageAtPathAsJPG(anImage, outPath, qulityNum as real)
  set imageRep to anImage’s TIFFRepresentation()
  
set aRawimg to current application’s NSBitmapImageRep’s imageRepWithData:imageRep
  
set pathString to current application’s NSString’s stringWithString:outPath
  
set newPath to pathString’s stringByExpandingTildeInPath()
  
set myNewImageData to (aRawimg’s representationUsingType:(current application’s NSJPEGFileType) |properties|:{NSImageCompressionFactor:qulityNum})
  
set aRes to (myNewImageData’s writeToFile:newPath atomically:true) as boolean
  
return aRes –true/false
end saveNSImageAtPathAsJPG

–与えられたファイルパスのJPEG画像をASCII ARTに変換して返す
on jpegToAsciiArt(anImageAlias, digitNum as integer)
  set sText to “/usr/local/bin/jp2a -f –html-raw –colors –width=” & (digitNum as string) & ” -i “ & quoted form of POSIX path of anImageAlias
  
set tRes to do shell script sText
  
return tRes
end jpegToAsciiArt

–スタイル付きテキストを指定フォルダ(POSIX path)にRTFで書き出し
on saveStyledTextAsRTF(aFileName, targFol, aStyledString)
  –Convert NSMutableStyledStrings to RTF
  
set bstyledLength to aStyledString’s |string|()’s |length|()
  
set bDict to current application’s NSDictionary’s dictionaryWithObject:“NSRTFTextDocumentType” forKey:(current application’s NSDocumentTypeDocumentAttribute)
  
set bRTF to aStyledString’s RTFFromRange:(current application’s NSMakeRange(0, bstyledLength)) documentAttributes:bDict
  
  
– build path based on title
  
set theName to current application’s NSString’s stringWithString:aFileName
  
set theName to theName’s stringByReplacingOccurrencesOfString:“/” withString:“_”
  
set theName to theName’s stringByReplacingOccurrencesOfString:“:” withString:“_”
  
set thePath to current application’s NSString’s stringWithString:targFol
  
set thePath to (thePath’s stringByAppendingPathComponent:theName)’s stringByAppendingPathExtension:“rtf”
  
  
return (bRTF’s writeToFile:thePath atomically:true) as boolean
end saveStyledTextAsRTF

★Click Here to Open This Script 

2016/05/17 Duet DisplayのMac側プロセスの死活判定を定期的に実行

iOS用のDuet Displayは、iOSデバイスをUSB経由でMac/Windows機とつなぎ、iOSデバイスを外部ディスプレイ化するアプリです。

AppStoreで1,900円(記事作成時現在の価格)でiOSアプリを購入+インストール、Mac側にはDuet Displayのホームページから無料ダウンロード可能なツールをインストールします。

このDuet Displayを使って、ちょっと使い道のなかったiPadなどをMacのサブディスプレイにすることができます。以前は、Air Displayを使って無線LAN経由でiPadを外部ディスプレイ化してもみましたが、パフォーマンスがいまいちなうえにソフトウェアの安定性が残念なレベルだったので使用をやめてしまいました。

img_3577_resized.png

Duet Displayはさすがにゲームを快適に行えるほどではありませんが、ちょっとした用途であれば違和感なく使えるパフォーマンス。

3・4日ほどは便利に使っていたものの、途中でMac側のduetプロセスがコケたりして、急にディスプレイ表示が消える現象に直面。サブディスプレイとして使っている場合には冗談ぐらいで済みますが、メインディスプレイとして使っていた場合には悲惨です(メインディスプレイとして使ってほしくない雰囲気)。

いろいろ実験(長期間起動させっぱなしとか、スリープからの回復を連続して行うとか)を行ったところ、duetプロセスが落ちることは避けられないという結論に至りました(落ちるものは落ちる)。

そこで、Mac側のduetプロセスの死活判定を定期的に行い、死んでいた場合には起動し直すAppleScriptアプレットを作って運用してみました。このプロセス死活判定は、以前に作成したものを使いまわしたため、プログラムはほぼ2〜3行追加しただけです。

このような仕組みを用意したおかげで、iPadをMac miniのメインディスプレイに設定して、duetプロセスがコケて表示が消えても自動で表示が回復するようになりました。idleハンドラ内のタイマー割り込み時間(秒)を現在は10秒にしていますが、もうちょっと短い間隔でチェックしてもよいと思います。

本AppleScriptはスクリプトエディタで「アプリケーション」として保存し、オプションで「ハンドラの実行後に終了しない」を指定することで立ち上げっぱなしの運用が可能です。また、Dock上から「ログイン時に開く」にチェックすることで、電源オン時→ログイン時に自動起動されるため、おすすめです。

AppleScript名:restartDuet
on run
  idle
end run

on idle
  set aRes to detectAppAliveByID(“com.kairos.duet”) of me
  
if aRes is not equal to true then
    tell application id “com.kairos.duet” to launch
  end if
  
return 10
end idle

–指定プロセスの死活判定(Bundle IDで判定)
on detectAppAliveByID(aProcBundleID)
  set aProcBundleID to aProcBundleID as string
  
  
–Phase 1 psコマンド経由で状態を確認してみる
  
set aRes to false
  
try
    tell application “System Events”
      set aList to bundle identifier of every process
      
if aProcBundleID is in aList then
        
        
set tmpList to name of every process whose bundle identifier = aProcBundleID
        
set aProcName to contents of first item of tmpList
        
        
set aRes to true
        
tell process aProcName
          set processID to unix id –プロセスIDを取得
        end tell
        
        
set processID to processID as string
        
        
–指定プロセスがゾンビプロセス化しているかどうかを判定
        
set procState to (words of (do shell script “/bin/ps “ & processID & ” | cut -d ’ ’ -f 6″)) as string
        
        
if procState contains “Z” then
          –ゾンビプロセスを殺す
          
do shell script “/bin/kill -9 “ & processID
          
return “killed”
        end if
      else
        –指定したBundle IDのプロセスが存在しない場合falseでリターン
        
return false
      end if
    end tell
  on error
    –異常発生時にはさっさとリターン
    
return false
  end try
  
  
–Phase 2 指定アプリに直接コンタクトして反応を見る
  
try
    with timeout of 3 seconds
      tell application id aProcBundleID
        set aTmpvar to name –これができない(Scriptableな)アプリはほとんどないだろう(多分)
      end tell
    end timeout
  on error
    –名称を取得できなかった場合にはコケていると見なしてプロセスを殺す
    
do shell script “/bin/kill -9 “ & processID
    
return “killed”
  end try
  
  
return aRes
end detectAppAliveByID

★Click Here to Open This Script 

2016/04/06 指定のDiskの情報を取得する

diskutilコマンドの結果をparseして、指定のデバイス名のdiskの情報を取得するAppleScriptです。

デバイス名はbsdレイヤーで利用している/dev/xxxxxといった名前であり、マウント中の光学メディア(CD-R、DVD-R、BD-Rなど)のbsdデバイス名を求めるのはちょっと手間がかかります。本来なら、choose folderコマンドで指定したドライブ(に含まれているフォルダ)からbsdデバイス名を求めて処理・・・をしたかったのですが、時間がなかったのでとりあえず決め打ちで。

とりあえず、指定のドライブに入っている光学メディアの種類(Optical Media Type)と、光学ドライブ側がサポートしているメディアの種類(Optical Drive Type)を取得できます。結果がNSDictionaryになっているため、Script Editor上では内容を確認できません。AppleScriptネイティブのrecord型のデータだと属性ラベルの自由度が低いため(属性ラベルに空白文字とか入りませんし)、NSDictionaryのままにしてあります。

AppleScript名:指定のDiskの情報を取得する
– Created 2016-04-06 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set targDev to “/dev/disk3″ –Blu-ray drive via USB

set aDict to current application’s NSMutableDictionary’s alloc()’s init()
set a to do shell script “diskutil info “ & targDev
set aList to paragraphs of a

repeat with i in aList
  set j to contents of i
  
if j is not equal to “” then
    set jj to parseByDelim(j, “:”) of me
    
    
if (count every item of jj) is equal to 2 then
      copy jj to {j2, j3}
      
      
set jj2 to (current application’s NSString’s stringWithString:j2)
      
set jj3 to (current application’s NSString’s stringWithString:j3)
      
      
set jjj2 to (jj2’s stringByTrimmingCharactersInSet:(current application’s NSCharacterSet’s whitespaceCharacterSet()))
      
set jjj3 to (jj3’s stringByTrimmingCharactersInSet:(current application’s NSCharacterSet’s whitespaceCharacterSet()))
      
      (
aDict’s setValue:jjj3 forKey:jjj2)
    end if
    
  end if
end repeat

return aDict
–>  (NSDictionary) {Read-Only Media:”Yes”, OS Can Be Installed:”No”, Volume Name:”Not applicable (no file system)”, OS 9 Drivers:”No”, Virtual:”No”, Device Block Size:”2048 Bytes”, Low Level Format:”Not supported”, Removable Media:”Yes”, Device / Media Name:”MATSHITA BD-MLT UJ240AS”, Optical Media Erasable:”No”, Optical Drive Type:”CD-ROM, CD-R, CD-RW, DVD-ROM, DVD-R, DVD-R DL, DVD-RW, DVD-RAM, DVD+R, DVD+R DL, DVD+RW, BD-ROM, BD-R, BD-RE”, Part of Whole:”disk3″, Device Identifier:”disk3″, Whole:”Yes”, Optical Media Type:”BD-R”, SMART Status:”Not Supported”, Device Location:”External”, Volume Free Space:”Not applicable (no file system)”, Device Node:”/dev/disk3″, Read-Only Volume:”Not applicable (no file system)”, Media Type:”Generic”, Total Size:”0 B (0 Bytes) (exactly 0 512-Byte-Units)”, Media Removal:”Software-Activated”, Mounted:”Not applicable (no file system)”, Content (IOContent):”None”, File System:”None”, Protocol:”USB”}

–テキストを指定デリミタでリスト化
on parseByDelim(aData, aDelim)
  set aText to current application’s NSString’s stringWithString:aData
  
set aList to aText’s componentsSeparatedByString:aDelim
  
return aList as list
end parseByDelim

★Click Here to Open This Script 

2015/08/25 MacのHardware UUIDを取得する

Macのハードウェアを一意に特定する、Hardware UUIDを取得するAppleScript(shellを呼んでいるだけ)です。

uuid1.png
▲Appleメニューの「このMacについて」を実行。このWindowの下部にあるボタン「システムレポート…」をクリックすると…

uuid2.png
▲「ハードウェアの概要:」で「ハードウェアUUID」が表示されます

アプリケーションの中に入れて呼ぶ可能性については想定していませんが、ツール的にメニューから呼び出して使うことは考えています。たとえば、自分が参加している(知り合いの作者が行っている)ソフトウェアのβテスト時に、ソフトウェアの作者に伝えるような用途です。

shell呼び出しをなくす方向でいろいろ調べてはみたのですが、ASOCで扱えないCFStringなどの機能を用いているサンプルコードしか見当たりませんでした。残念!

AppleScript名:MacのHardware UUIDを取得する
– Created 2015-08-25 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions

set sText to “/usr/sbin/ioreg -rd1 -c IOPlatformExpertDevice | /usr/bin/awk ’/IOPlatformUUID/ { print $3; }’”
set aRes to do shell script sText
–>  ”\”XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\”"

★Click Here to Open This Script 

2015/08/09 使用中のMacの製品呼称を取得する

使用中のMacの製品呼称を取得するAppleScriptです。

本来は、Cocoaの機能を呼び出してXMLをparseしようとしてこの数倍のプログラムを組んでいたのですが、いまひとつうまくいかずに挫折。System Eventsでparseするという安直な方法に落ち着きました(^ー^;;

→ ここの情報を参照しました

製品呼称コードは4文字パターン(例:DKQ2)と3文字パターン(例:5RU)があるようなので、シリアル番号から両方の文字列を作成して、両方試すと確実ではないでしょうか。

MacBook Air 2014で実行すると、「MacBook Air」としか返してこないことを確認、、、、いろいろ例外がありそうです。

AppleScript名:使用中のMacの製品呼称を取得する
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set aSerial to retSerial()
set aID to text ((length of aSerial) - 3) thru -1 of aSerial

set aRes to do shell script “curl -o - http://support-sp.apple.com/sp/product?cc=” & aID & “&lang=en_US”
–> “<?xml version=\”1.0\” encoding=\”utf-8\” ?><root><name>CPU Name</name><configCode>MacBook Pro (Retina, Mid 2012)</configCode><locale>en_US</locale></root>”

tell application “System Events”
  set aData to make new XML data with properties {text:aRes}
  
set aModel to value of XML element “configCode” of XML element “root” of aData
end tell
–> “MacBook Pro (Retina, Mid 2012)”

–Get Your Mac’s Hardware Serial Code
on retSerial()
  set a to (do shell script “system_profiler SPHardwareDataType | grep Serial”)
  
set b to offset of “:” in a
  
set c to (characters (b + 2) thru -1 of a) as text
  
return c
end retSerial

★Click Here to Open This Script 

2015/08/07 CPUの詳細な型番を取得する

CPUの詳細な型番情報を取得するAppleScriptです(shell commandを呼んでいるだけ)。

新製品が登場したときとか、Apple Storeで自分の持っていないMacのCPUの型番をしらべてベンチマーク値を調べる時などに有用な情報です。

AppleScript名:CPUの詳細な型番を取得する
do shell script “sysctl -n machdep.cpu.brand_string”
–> “Intel(R) Core(TM) i7-3720QM CPU @ 2.60GHz” # MacBook Pro Retina 2012

★Click Here to Open This Script 

2015/08/06 指定の画像を別形式に変換する v3

指定の画像を別形式に変換するAppleScriptのアップデート版です。Shane Stanleyからツッコミがあって、一部(無意味な処理を削除するなどの)修正をしています。

v2で使っていた「連番の追加によるファイル名の重複回避」ルーチン「chkExistAndIncrementChildNumber(aa)」内において、

set bRes to ((tmpStr’s caseInsensitiveCompare:eStr) is not equal to (current application’s NSOrderedSame)) as boolean

の処理を行っていましたが、冷静に考えればここでこの処理を行う必然性がないので削除。その他、さまざまな場所にあった「as string」を念のために「as text」に置き換え。また、chkExistAndIncrementChildNumberの名称を少し変更しました。こうして、徐々に完成度が上がっていったものについてはライブラリに突っ込んで使い回すことになることでしょう。

AppleScript名:指定の画像を別形式に変換する v3
– Created 2015-08-05 by Takaaki Naganoya
– Modified 2015-08-06 by Shane Stanley
– 2015 Piyomaru Software

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set targFormat to “pdf”
set aImage to choose file of type {“public.image”} with prompt (“Choose image file to convert to “ & targFormat & “.”)
set aRes to convertImageToANY(aImage, targFormat) of me
–> “/Users/me/Desktop/301b3607.pdf”
–> “/Users/me/Desktop/301b3607_1.pdf” (同一ファイルの変換を2度行った結果、子番号を付与して衝突を回避)

–指定の画像をsipsで別形式に変換する
on convertImageToANY(aImage as alias, outFormat as text)
  
  
set aExt to chkExtension(outFormat) of me
  
if aExt = false then return false
  
  
tell application “Finder”
    set bExt to name extension of aImage
  end tell
  
–指定画像と変換後の画像フォーマットが同じだった
  
set bExt to chkExtension(bExt) of me
  
if aExt = bExt then return “There is no need to convert (same format)”
  
if bExt = false then return false –出力ファイルフォーマットエラー
  
  
–変換後のファイル名として、オリジナルの拡張子を新規拡張子に付け替え
  
set bImagePosix to POSIX path of aImage
  
set bPathString to current application’s NSString’s stringWithString:bImagePosix
  
set newPath to ((bPathString’s stringByDeletingPathExtension()) as text) & “.” & aExt
  
  
–新規ファイル作成時にファイルの重複があるかチェック。存在する場合にはファイル名に子番号を付与して重複を回避する
  
set newPath to chkExistAndAddIncrementalChildNumber(newPath)
  
  
set sText to “sips -s format “ & aExt & ” “ & quoted form of POSIX path of aImage & ” –out “ & quoted form of newPath
  
  
try
    do shell script sText
  on error erM
    return false –shell scriptの実行時にエラーが発生した
  end try
  
  
return newPath
  
end convertImageToANY

–複数表記形式のファイル名拡張子のチェックおよびsipsが受付可能なものに変換
on chkExtension(aExtension)
  –acceptable file name extensions
  
set formatList to {{“jpeg”, “jpg”}, {“tiff”, “tif”}, {“png”}, {“gif”, “giff”}, {“jp2″}, {“pict”}, {“bmp”}, {“qtif”}, {“psd”}, {“sgi”}, {“tga”}, {“pdf”}}
  
set hitF to false
  
  
ignoring case
    repeat with i in formatList
      set j to contents of i
      
if aExtension is in j then
        set aExt to contents of first item of j
        
set hitF to true
        
exit repeat
      end if
    end repeat
  end ignoring
  
  
if hitF = false then
    return false –No Hit  
  else
    return aExt –Hit
  end if
  
end chkExtension

–連番の追加によるファイル名の重複回避
on chkExistAndAddIncrementalChildNumber(aa)
  set aStr to current application’s NSString’s stringWithString:aa
  
  
–ファイルパス(フルパス)からファイル名部分を取得
  
set bStr to aStr’s lastPathComponent()
  
–> “P0000_000.csv”
  
  
–ファイル名から拡張子を取得
  
set cStr to (bStr’s pathExtension()) as text
  
–> “csv”
  
  
–ファイル名から拡張子を削除
  
set dStr to (bStr’s stringByDeletingPathExtension()) as text
  
–> “P0000_000″
  
  
–ファイルパス(フルパス)から親フォルダを取得(ただし末尾はスラッシュになっていない)
  
set eStr to (aStr’s stringByDeletingLastPathComponent()) as text
  
–>  ”/Users/me/Desktop”
  
  
set aManager to current application’s NSFileManager’s defaultManager()
  
set aRes to (aManager’s fileExistsAtPath:aStr) as boolean
  
if aRes = false then return aa –重複がない場合、与えられたフルパスをそのまま返す
  
  
  
–ファイル名の重複があった場合の重複回避処理  
  
set hitF to false
  
repeat with i from 1 to 65535
    
    
set tmpPath to (eStr & “/” & dStr & “_” & (i as text) & “.” & cStr)
    
set tmpStr to (current application’s NSString’s stringWithString:tmpPath)
    
set aRes to (aManager’s fileExistsAtPath:tmpStr) as boolean
    
    
if aRes = false then
      set hitF to true
      
exit repeat
    end if
    
  end repeat
  
  
if hitF = false then return false –65,535回繰り返したがファイル名の衝突を回避できなかった、など
  
  
return tmpStr as text
  
end chkExistAndAddIncrementalChildNumber

★Click Here to Open This Script 

2015/08/05 指定の画像を別形式に変換する v2

指定の画像を別形式に変換するAppleScriptのアップデート版です(前バージョンはこちら)。

(儡晃紊離侫.ぅ詭召髻aaa.jpg→aaa.jpg.pdf」から「aaa.jpg→aaa.pdf」となるよう拡張子の付け替えを行うようにしました

∧儡晃紊離侫.ぅ詭召粘存のファイル名との衝突が発生する場合には、子番号を付与して衝突を回避するようにしました(子番号は最大で65,535)

AppleScript名:指定の画像を別形式に変換する v2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

set targFormat to “pdf”
set aImage to choose file of type {“public.image”} with prompt (“Choose image file to convert to “ & targFormat & “.”)
set aRes to convertImageToANY(aImage, targFormat) of me
–> “/Users/me/Desktop/301b3607.pdf”
–> “/Users/me/Desktop/301b3607_1.pdf” (同一ファイルの変換を2度行った結果、子番号を付与して衝突を回避)

–指定の画像をsipsで別形式に変換する
on convertImageToANY(aImage as alias, outFormat as string)
  
  
set aExt to chkExtension(outFormat) of me
  
if aExt = false then return false
  
  
tell application “Finder”
    set bExt to name extension of aImage
  end tell
  
–指定画像と変換後の画像フォーマットが同じだった
  
set bExt to chkExtension(bExt) of me
  
if aExt = bExt then return “There is no need to convert (same format)”
  
if bExt = false then return false –出力ファイルフォーマットエラー
  
  
–変換後のファイル名として、オリジナルの拡張子を新規拡張子に付け替え
  
set bImagePosix to POSIX path of aImage
  
set bPathString to current application’s NSString’s stringWithString:bImagePosix
  
set newPath to ((bPathString’s stringByDeletingPathExtension()) as text) & “.” & aExt
  
  
–新規ファイル作成時にファイルの重複があるかチェック。存在する場合にはファイル名に子番号を付与して重複を回避する
  
set newPath to chkExistAndIncrementChildNumber(newPath)
  
  
set sText to “sips -s format “ & aExt & ” “ & quoted form of POSIX path of aImage & ” –out “ & quoted form of newPath
  
  
try
    do shell script sText
  on error erM
    return false –shell scriptの実行時にエラーが発生した
  end try
  
  
return newPath
  
end convertImageToANY

–複数表記形式のファイル名拡張子のチェックおよびsipsが受付可能なものに変換
on chkExtension(aExtension)
  –acceptable file name extensions
  
set formatList to {{“jpeg”, “jpg”}, {“tiff”, “tif”}, {“png”}, {“gif”, “giff”}, {“jp2″}, {“pict”}, {“bmp”}, {“qtif”}, {“psd”}, {“sgi”}, {“tga”}, {“pdf”}}
  
set hitF to false
  
  
ignoring case
    repeat with i in formatList
      set j to contents of i
      
if aExtension is in j then
        set aExt to contents of first item of j
        
set hitF to true
        
exit repeat
      end if
    end repeat
  end ignoring
  
  
if hitF = false then
    return false –No Hit  
  else
    return aExt –Hit
  end if
  
end chkExtension

–連番の追加によるファイル名の重複回避
on chkExistAndIncrementChildNumber(aa)
  set aStr to current application’s NSString’s stringWithString:aa
  
  
–ファイルパス(フルパス)からファイル名部分を取得
  
set bStr to aStr’s lastPathComponent()
  
–> “P0000_000.csv”
  
  
–ファイル名から拡張子を取得
  
set cStr to (bStr’s pathExtension()) as string
  
–> “csv”
  
  
–ファイル名から拡張子を削除
  
set dStr to (bStr’s stringByDeletingPathExtension()) as string
  
–> “P0000_000″
  
  
–ファイルパス(フルパス)から親フォルダを取得(ただし末尾はスラッシュになっていない)
  
set eStr to (aStr’s stringByDeletingLastPathComponent()) as string
  
–>  ”/Users/me/Desktop”
  
  
set aManager to current application’s NSFileManager’s defaultManager()
  
set aRes to (aManager’s fileExistsAtPath:aStr) as boolean
  
if aRes = false then return aa
  
  
set hitF to false
  
repeat with i from 1 to 65535
    
    
set tmpPath to (eStr & “/” & dStr & “_” & (i as string) & “.” & cStr)
    
set tmpStr to (current application’s NSString’s stringWithString:tmpPath)
    
set aRes to (aManager’s fileExistsAtPath:tmpStr) as boolean
    
set bRes to ((tmpStr’s caseInsensitiveCompare:eStr) is not equal to (current application’s NSOrderedSame)) as boolean
    
    
if {aRes, bRes} = {false, true} then
      set hitF to true
      
exit repeat
    end if
    
  end repeat
  
  
if hitF = false then return false
  
  
return tmpStr as string
  
end chkExistAndIncrementChildNumber

★Click Here to Open This Script 

2015/08/04 指定の画像を別形式に変換する

指定の画像を別形式に変換するAppleScriptです。

OS XにはAppleScriptから制御できる専用の画像処理アプリケーション(GUIなし)である「Image Events」(sipsのラッパー)がありますが、なぜかImage EventsにはPDFへの変換機能が実装されていないため(sipsにはある)、著作権情報やファイルのオープンコントロール(パスワード設定)など細かいことを考えずにただPDFに変換するだけのものを作成。

さらにsipsがサポートしている画像形式かどうかのチェックを行うルーチンを付加して、「どの形式へ」変換するかを自由に( {{”jpeg”, “jpg”}, {”tiff”, “tif”}, {”png”}, {”gif”}, {”jp2″}, {”pict”}, {”bmp”}, {”qtif”}, {”psd”}, {”sgi”}, {”tga”}, {”pdf”}}の中でチェック)指定できるようにしてみました。

Photoshop上でR=255のRGB TIFF画像(真っ赤な単色塗り画像)を作成して、sRGBのICCプロファイルを添付。これを本ルーチンでPDF、JPEG、PNG、BMP、PSD、GIFに変換してみたところ、JPEGがR=254になった以外は色の変化はありませんでした。

red255tif.png

sips自体にはICC Profileの変換機能もあるため、もう少しいろいろチューニングが行えることでしょう。

AppleScript名:指定の画像を別形式に変換する
use AppleScript version “2.4″
use scripting additions

set targFormat to “pdf”
set aImage to choose file of type {“public.image”} with prompt (“Choose image file to convert to “ & targFormat & “.”)
set aRes to convertImageToANY(aImage, targFormat) of me
–> “Macintosh HD:Users:me:Desktop:1D1800F7-2755-4CFB-8322-F7EE0D64D570.jpg.pdf”

–指定の画像をsipsで別形式に変換する
on convertImageToANY(aImage as alias, outFormat as string)
  
  
set aExt to chkExtension(outFormat) of me
  
if aExt = false then return false
  
  
set bImage to (aImage as text) & “.” & aExt
  
tell application “Finder”
    set bExt to name extension of aImage
  end tell
  
  
–指定画像と変換後の画像フォーマットが同じだった
  
set bExt to chkExtension(bExt) of me
  
if aExt = bExt then return “There is no need to convert (same format)”
  
if bExt = false then return false –出力ファイルフォーマットエラー
  
  
set sText to “sips -s format “ & aExt & ” “ & quoted form of POSIX path of aImage & ” –out “ & quoted form of POSIX path of bImage
  
  
try
    do shell script sText
  on error erM
    return false –shell scriptの実行時にエラーが発生した
  end try
  
  
return bImage
  
end convertImageToANY

–複数表記形式のファイル名拡張子のチェックおよびsipsが受付可能なものに変換
on chkExtension(aExtension)
  –acceptable file name extensions
  
set formatList to {{“jpeg”, “jpg”}, {“tiff”, “tif”}, {“png”}, {“gif”, “giff”}, {“jp2″}, {“pict”}, {“bmp”}, {“qtif”}, {“psd”}, {“sgi”}, {“tga”}, {“pdf”}}
  
set hitF to false
  
  
ignoring case
    repeat with i in formatList
      set j to contents of i
      
if aExtension is in j then
        set aExt to contents of first item of j
        
set hitF to true
        
exit repeat
      end if
    end repeat
  end ignoring
  
  
if hitF = false then
    return false –No Hit  
  else
    return aExt –Hit
  end if
  
end chkExtension

★Click Here to Open This Script 

2015/05/17 メモリー解放?

使っていないメモリーの解放を促す(?)AppleScriptです。

OS X, Yosemiteのメモリー管理がうまくないのか、以前よりもメモリー不足に陥るケースが増えてきました。OS X 10.10.x搭載のMac miniなどでAppleScriptによる常時稼働の自動処理ロボットを運用している際に、最低環境のメモリー4GBで運用しているときついケースもあります。

memoryusage.png
▲搭載メモリー8GBのMacBook Pro Retinaでもメモリー解放ユーティリティが欠かせない。ただし、この手のソフトはTerminalやAppleScriptから呼び出せない

長期間連続運転しているとメモリー上のゴミも増えるわけで、各種メモリー解放ソリューションを自動処理システムにも導入したくなります。

世間的に、「これを実行するとメモリーが解放される」とされているものは、メモリー解放専用のコマンドではなく、別の働きをするものを実行するとなぜかメモリーが解放されるといった「民間療法」レベルの話が多く、本当にメモリーを解放できるかどうかは眉ツバものです。

メモリー解放効果があるとされているコマンドは、du(ディスク使用量報告)コマンド、purge(ディスクキャッシュのdiskへの書き戻し)コマンド、あとはkillallコマンドでdockやFinderのプロセスをkillするとか(FinderのKillはけっこういい気がする)。

とりあえず、自動処理システムに組み込めるようにハンドラで呼べるようにして、メモリー解放度合いを計測できるようにしてみました。

実際に呼び出してメモリー解放度合いを計測していますが、効果のある場合もあればない場合もあったりで、こんなもんに頼るよりも「メモリー搭載量の多いマシン」で自動処理するほうが正解だったり、定期的に自動でシステムの再起動を行ったほうが効果的だったりで、なかなか頭が痛いところです。

そういう意味で、現行モデルのMac miniのメモリーが増設できなくなったのは残念です、、、、あるいは、最低構成を8GBに変更すべき(新MacBookのように)。

AppleScript名:メモリー解放?
set aRec to getMemStatus()
–> {usedMem:”7068M”, usedMemFixed:”1205M”, freeMem:”1115M”}

freeMem1(20) of me

set bRec to getMemStatus()
–>{usedMem:”6343M”, usedMemFixed:”1236M”, freeMem:”1840M”}

–メモリー解放?
on freeMem1(sleepSec as integer)
  set sText to “du -sx / &> /dev/null & sleep “ & (sleepSec as string) & ” && kill $!”
  
try
    do shell script sText
  end try
end freeMem1

–メモリー状況の確認
on getMemStatus()
  set memoryStatus to do shell script “top -l 1 | head -10 | grep PhysMem”
  
set usedMem to word 2 of memoryStatus
  
set wiredMem to word 4 of memoryStatus
  
set unusedMem to word 6 of memoryStatus
  
return {usedMem:usedMem, usedMemFixed:wiredMem, freeMem:unusedMem}
end getMemStatus

★Click Here to Open This Script 

2015/04/23 Macのモデル名を返す

Macのモデル名を返すAppleScriptです。Mac Pro/Mac mini/iMac/MacBook Pro/MacBook Air/MacBook などのざっくりしたモデル名(マシン種別)です。

AppleScript名:Macのモデル名を返す
–By Christopher Stone <listmeister@thestoneforge.com>
–2011/09/15

set aModelName to getModelName()
–> "MacBook Pro"

on getModelName()
  # Keeping the hardware data record:
  
set hardwareData to do shell script "system_profiler SPHardwareDataType" without altering line endings
  
set cmd to "sed -nE ’/Model Name/p’ <<< " & quoted form of hardwareData & " | sed -E ’s/^ +//’"
  
set macModel to do shell script cmd
  
  
# One-liner:
  
set macModel to do shell script "system_profiler SPHardwareDataType | sed -nE ’/Model Name/p’| sed -E ’s/^ +//’"
  
  
return (text 13 thru -1 of macModel) –Skip "Model Name: " strings
  
end getModelName

★Click Here to Open This Script 

2015/04/22 Spotlight検索インデックスを再生成

起動ディスクのSpotlight検索インデックスを再生成するAppleScriptです。ふつうに、スクリプトエディタ上で実行するものです。実行時に管理者パスワードの入力を求められます。

さまざまなマシン環境を見たときに、Spotlightの検索インデックスが「壊れている」マシンを見かけることがあります。こうなると、mdfindコマンドでspotlightの機能を呼び出して、指定のファイルを見つけ出す処理が有効に機能しません。このような場合には、インデックスの再生成が必要になります。

Spotlightのインデックス再生成は、システム環境設定で行うようになっており、そのものズバリの名前がついていないため、ひじょうに分かりにくくなっています。

そのため、説明を省くことを目的にAppleScriptで書いておきました。Terminalが使えないユーザーでも、スクリプトを実行するだけなら可能でしょう。

ただし、Spotlight復旧のためにはSpotlightのインデックス再生成のほか、ディスクユーティリティーで「ユーザー権限の修復」を行う必要があったり、そもそも起動ディスクの一部のセクタが損傷しているケースなどもあり、「万能薬」ではないことに注意が必要です。

AppleScript名:Spotlight検索インデックスを再生成
do shell script “mdutil -E /” with administrator privileges

★Click Here to Open This Script 

2015/04/12 OS X 10.10.3のdelayに(新たな)バグ? マウスカーソルの移動でdelayがキャンセルされる

Twitterへの@fixdotさんの投稿についてやりとりしつつ検証したところ、OS X 10.10.3の新たなバグらしきものが明らかになりました(以前からあったものかは不明)。@fixdotさんの(この)投稿内容が正しいことが証明されました。

step1:以下のScriptをアプリケーション形式で保存

AppleScript名:delayTest
display dialog “test1″ giving up after 1
delay 10
display dialog “test2″ giving up after 1

★Click Here to Open This Script 

step2: 保存したアプリケーション(アプレット)を実行
step3: (実行中に)マウスカーソルを移動させる

・・・アプレットをの実行中にマウスカーソルを移動させると、delayの待ち時間が無視されます(ーー;

とりあえず、広く言われている対策をスマートに実装するとこんな感じです。do shell script “sleep”に置き換えろ、というのが解決策なんですが、プログラムの書き換えを最低限にとどめるために、on delayでdelay命令そのものをのっとってdo shell scriptコマンドを実行します。

AppleScript名:delayTest_対策
display dialog “test1″ giving up after 1
delay 10
display dialog “test2″ giving up after 1

on delay aParam
  do shell script “sleep “ & aParam
end delay

★Click Here to Open This Script 

2015/02/02 カレンダー.app(旧称iCal)で選択中のイベントの情報を取得

海外のBlogで、カレンダー.app(Calendar.app)の画面上で選択中のイベントの情報を取得するAppleScriptが公開されていました。

→ Reference selected Calendar events in AppleScript

カレンダー.appのAppleScript用語辞書にはselectionとかselected eventなどの予約語が用意されておらず、そのうえ「リマインダー.app」とイベントが共有されており区別できないなど、Apple純正アプリとしてはかなり「残念な出来」になっている筆頭残念アプリケーションです。

同Blogによれば、AppleScript用語辞書にselectionなどのプロパティは存在しないのに、設定ファイル”com.apple.ical.plist”には「SelectedEvents」のエントリが存在しているので、それをdefaults readコマンドで読み取って、parseして、sqlite3経由でsqlを発行して該当するイベントの情報を取得するのだとか。

・・・ここまでしないと取得できないことを嘆くべきか、存在しない機能を実現した努力を讃えるべきなのか、そもそも最初からselectionの機能があるべきという主張をすべきなのか、なかなか悩ましいところです。

カレンダー.app上でイベントを選択して同AppleScriptを実行してみたところ、どうも「選択中のイベントを取得できる」ときと「できない」ときがあります。ソース中にもそのように書いてあり、いろいろ試行錯誤してみたところ・・・

数行追加したら、バッチリ取れるようになりました。ただ、フィードバックするにも同Blogはコメント読んでないようで・・・修正版を掲載しておきます。オリジナルのScriptでは、取得した「選択中のイベント」の発生15分前にアラームを鳴らすようにしてありましたが、変更されるのがいやだったのでコメントアウトしてあります。

AppleScript名:カレンダー.app上で選択中のイベントを取得する
–https://www.johneday.com/1086/reference-selected-calendar-events-applescript
– Title: Reference selected Calendar events in AppleScript
– Created 2015-02-02 by @johneday on Twitter
– Modified 2015-02-02 by Takaaki Naganoya

use AppleScript version "2.4"
use scripting additions

——————————
– ABOUT
——————————
– Written and tested in Yosemite, Calendar Version 8.0
– The plist may take several seconds to update after a new event has been selected.
– Only the first instance of a recurring event will be referenced.

——————————-
– Modify by Takaaki Naganoya
——————————
tell application "Calendar"
  if running = false then return
  
activate
end tell
do shell script "sync"

——————————-
– MAIN CODE
——————————
set defaultsReply to (do shell script "defaults read com.apple.ical SelectedEvents")
set selectedEvents to parseDefaults(defaultsReply)

if selectedEvents = {} then
  display notification "Please try again" with title "No Calendar Event Selected"
  
return
end if

set eventReferenceList to {}
repeat with sEvent in selectedEvents
  set {eventID, calendarID} to sqlQuery(sEvent)
  
tell application "Calendar"
    set eventReference to event id eventID of calendar id calendarID
    
– INSERT YOUR CODE TO PROCESS EACH EVENT
    
    – Example of "Alert 15 minutes before start"
    
–my addDisplayAlarm(eventReference, -15)
    
    – OR BUILD A LIST OF EVENTS
    
set end of eventReferenceList to eventReference
  end tell
end repeat
return eventReferenceList

——————————
– HANDLERS
——————————
on parseDefaults(resultText)
  set localUIDs to {}
  
set {TID, text item delimiters} to {text item delimiters, quote}
  
set resultItems to text items of resultText
  
set text item delimiters to TID
  
repeat with i from 1 to (count resultItems)
    if i mod 2 = 0 then set end of localUIDs to resultItems’s item i
  end repeat
  
return localUIDs
end parseDefaults

on sqlQuery(localUID)
  local dateString, localUID
  
if localUID contains "/" then
    set {TID, text item delimiters} to {text item delimiters, "/"}
    
set {dateString, localUID} to text items of localUID
    
set text item delimiters to TID
  end if
  
  set sqlText to "
SELECT DISTINCT zcalendaritem.zshareduid AS eventID
, znode.zuid as calID
FROM zcalendaritem
JOIN znode
ON znode.z_pk = zcalendaritem.zcalendar
AND zcalendaritem.zlocaluid = ’" & localUID & "’
;"
  
  set sqlPath to POSIX path of (path to library folder from user domain) & "Calendars/Calendar Cache"
  
set {TID, text item delimiters} to {text item delimiters, "|"}
  
set {eID, cID} to text items of (do shell script "echo " & quoted form of sqlText & " | sqlite3 " & quoted form of sqlPath)
  
set text item delimiters to TID
  
return {eID, cID}
end sqlQuery

on addDisplayAlarm(myEvent, triggerInterval)
  tell application "Calendar"
    tell myEvent
      if not (exists (display alarms whose trigger interval = triggerInterval)) then
        set myAlarm to make new display alarm at end of display alarms with properties {trigger interval:triggerInterval}
      end if
    end tell
  end tell
end addDisplayAlarm

★Click Here to Open This Script 

2015/01/24 テキストをhexdump

テキストをhexdumpするAppleScriptです。hexdumpしてからデータ処理するという方法は、案外まだまだ使える「手口」なので紹介しておきます(対象データがバカでかくないことが前提条件)。

fhexdump1.png

文字列の最後についている”0A”はLFですね。

AppleScript名:テキストをhexdump
set aStr to “あいうえお”
set aRes to retHexDumpedStr(aStr)
–> “E3 81 82 E3 81 84 E3 81 86 E3 81 88 E3 81 8A 0A “

–与えられたデータ内容をhexdumpして返す
on retHexDumpedStr(aStr)
  set aRes to do shell script “echo “ & quoted form of aStr & ” | hexdump -v -e ’/1 \”%02X \”’”
  
return aRes
end retHexDumpedStr

★Click Here to Open This Script 

2015/01/24 spotlightでファイルタグを指定してファイル一覧を取得

OS X 10.9, Mavericksで採用されたFinderのFile Tagで、指定フォルダ以下のファイルをリストアップするAppleScriptです。

だいたい、OS Xの新機能については1つのバージョンを置いてAppleScript側が追いつく、というスタイルが定着していたので、OS X 10.10でFile Tagのサポートがなかったことには(よくないほうの意味で)驚きました。

ただ、10.10で導入されたScript Editor上でのAppleScriptObjCの機能のサポートによって、File Tagの設定、取得、追加についてはAppleScriptObjCで書くもの、という認識を持っていました。

それでも、指定フォルダ以下のFile Tagによるファイル抽出については情報が出ていなかったので、いろいろと調べたところ・・・mdfindで検索するのが一番簡単という結論に。

filetag1.png

本来的には、フィルタ参照(get every file whose tags is equal to {”Blue”, “Green”} 的な)で抽出できることがAppleScript的な「作法」ではあるものの、Appleがそうした機能を提供していない(できていない)という状況に対処するためには、こうしたサブルーチンの利用が現実的でしょう。

ただ、{”グリーン”, “ブルー”, “ヤンキー”} というファイルタグを持つファイルが{”グリーン”, “ブルー”}でリストアップされてしまうので、まだ調整の余地がありそうです。

filetag2.png

などと書いたので、Finder上でSpotlightの動作を調べてみたら・・・この通りの動きをするようなので、仕方ないのかも、、

filetag3.png

AppleScript名:spotlightでファイルタグを指定してファイル一覧を取得
– Created 2015-01-24 by Takaaki Naganoya
use AppleScript version “2.4″
use scripting additions

set aFol to path to desktop
set aTagList to {“グリーン”, “ブルー”}
set aRes to getFileListByTagsWithSpotLight(aTagList, aFol) of me
–> {alias “Macintosh HD:Users:me:Desktop:fra5.png”, alias “Macintosh HD:Users:me:Desktop:fra6.png”}

–指定階層下で、指定タグ(複数をリストで指定)を持つファイルを取得(alias list)
on getFileListByTagsWithSpotLight(aTagList as list, startDir as {alias, string})
  –Error Case
  
if aTagList = {} then return {}
  
if startDir as string = “” then return
  
  
–Make File Tag Search Query String
  
set aQuery to {}
  
repeat with i in aTagList
    set aTag to contents of i
    
set aStr to “kMDItemUserTags==” & aTag
    
set the end of aQuery to aStr
  end repeat
  
set queryText to retArrowText(aQuery, ” && “) of me
  
  
–Make mdfind command string
  
set sDirText to quoted form of POSIX path of startDir
  
set shellText to “/usr/bin/mdfind ’” & queryText & “’ -onlyin “ & sDirText
  
try
    set aRes to do shell script shellText
  on error
    return {}
  end try
  
  
–Parse Result into alias list
  
set pList to paragraphs of aRes
  
set aList to {}
  
repeat with i in pList
    set aPath to POSIX file i
    
set aPath to aPath as alias
    
set the end of aList to aPath
  end repeat
  
return aList
  
end getFileListByTagsWithSpotLight

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to “”
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

★Click Here to Open This Script 

2014/12/25 アプリケーションごとのローカライズ言語数を求める

/Applicationsフォルダ以下の全アプリケーションのローカライズ言語数を求めて多い順にソートして返すAppleScriptです。

便利な部品ができてきたので、本来の用途以外に転用するのも簡単になってきました。

ただ、こういう「調査活動」以外にこの処理が生きるかどうかは未知数です、、、

OS X自体のローカライズ言語数=35ということが見て取れますが(ただし、対応言語は幾つかのレベルに分けられており、ユーザー数によって対応度が違うはず)、それ以上のローカライズ言語を持っているアプリケーションの存在が気になります。

AppleScript名:アプリケーションごとのローカライズ言語数を求める
– Created 2014-12-25 by Takaaki Naganoya

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

–/Applications以下のアプリケーションのパスをすべて求める
set apPath1 to (path to applications folder) as string
set aList to getFileListWithSpotLight(“kMDItemContentType”, “com.apple.application-bundle”, apPath1) of me

–各アプリケーションのローカリゼーション情報を取得(重複情報はカウントしつつ保持)
set aaList to {}

repeat with i in aList
  set j to contents of i
  
  
–アプリケーションのローカリゼーションを取得する(重複言語の除去ずみ)
  
set locList to getSpecifiedAppFilesLocalizationList(j) of me
  
  
tell application “System Events”
    set aName to name of j
  end tell
  
  
set the end of aaList to {aName, length of locList}
  
end repeat

–Sort Result (Many->Little)
set sortIndexes to {1} –Key Item id: begin from 0
set sortOrders to {false} –Descending Sort Order
set sortTypes to {“compare:”}
set rList to (current application’s SMSFord’s subarraysIn:aaList sortedByIndexes:sortIndexes ascending:sortOrders sortTypes:sortTypes |error|:(missing value)) as list

return rList
–> {{”VLC.app”, 93}, {”Creative Cloud.app”, 61}, {”Adobe Application Manager.app”, 61}, {”Google Drive.app”, 53}, {”Google Chrome.app”, 53}, {”Uninstall Product.app”, 43}, {”Uninstall Product.app”, 43}, {”Google Earth.app”, 42}, {”VueScan.app”, 40}, {”Evernote.app”, 40}, {”Adobe Muse CC 2014.app”, 37}, {”iTunes.app”, 35}, {”Digital Color Meter.app”, 35}, {”Image Capture.app”, 35}, {”Grab.app”, 35}, {”Game Center.app”, 35}, {”iBooks.app”, 35}, {”Boot Camp Assistant.app”, 35}, {”Bluetooth File Exchange.app”, 35}, {”System Information.app”, 35}, {”Safari.app”, 35}, {”Terminal.app”, 35}, {”Contacts.app”, 35}, {”Preview.app”, 35}, {”App Store.app”, 35}, {”Automator.app”, 35}, ……

–指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を排除
on getSpecifiedAppFilesLocalizationList(anAppAlias as alias)
  
  
set aURL to (current application’s SMSFord’s URLFrom:anAppAlias)
  
set aBundle to current application’s NSBundle’s bundleWithURL:aURL
  
  
set theNSLocale to current application’s NSLocale’s localeWithLocaleIdentifier:“en” –Output Locale Name in English (en)
  
  
–Get Localization Info
  
set locList to aBundle’s localizations()
  
–> {”de”, “English”, “fr”, “French”, “German”, “ja”, “Japanese”}
  
set theEnumerator to locList’s objectEnumerator()
  
  
set theSet to current application’s NSMutableSet’s |set|()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
    
set theName to (theNSLocale’s displayNameForKey:(current application’s NSLocaleIdentifier) value:aValue)
    
    
if theName is missing value then
      –”English”や”French”などは、missing valueが返ってくるので、”English”や”French”などをそのまま追加
      
theSet’s addObject:aValue
    else
      –”de”や”fr”などは、”German”や”French”が返ってくるので、それを追加
      
theSet’s addObject:theName
    end if
  end repeat
  
  
–NSCountedSetをNSMutableArrayに変換
  
set theArray to current application’s NSMutableArray’s array()
  
set theEnumerator to theSet’s objectEnumerator()
  
  
–NSMutableArrayから順次取り出して、NSArrayに出力
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
theArray’s addObject:aValue
  end repeat
  
  
return theArray as list
  
end getSpecifiedAppFilesLocalizationList

–指定階層下で、指定メタデータが指定パラメータであるファイルを取得(alias list)
on getFileListWithSpotLight(aMetaDataItem as string, aParam as string, startDir as {alias, string})
  set sDirText to quoted form of POSIX path of startDir
  
set shellText to “/usr/bin/mdfind ’” & aMetaDataItem & ” == \”" & aParam & “\”’ -onlyin “ & sDirText
  
try
    set aRes to do shell script shellText
  on error
    return {}
  end try
  
set pList to paragraphs of aRes
  
set aList to {}
  
repeat with i in pList
    set aPath to POSIX file i
    
set aPath to aPath as alias
    
set the end of aList to aPath
  end repeat
  
return aList
end getFileListWithSpotLight

★Click Here to Open This Script 

2014/12/25 アプリケーションのローカライズ分布を取得する v5

/Applicationsフォルダ内に入っているアプリケーションのローカライズ言語の度数分布を取得するAppleScriptのバージョンアップ版です。

1つのアプリケーションが複数の重複するローカライズ情報を持っているケース({”de”, “English”, “fr”, “French”, “German”, “ja”, “Japanese”})があり、1つのアプリケーションから情報を取得する段階で重複を除去するルーチンを作成。重複を排除して({”German”, “English”, “French”,”Japanese”})のように整理して取得するように変更しました。

また、/Applicationsフォルダの直下のアプリケーションのファイルしか取得していなかったので、mdfindで/Applicationsフォルダ以下すべてのアプリケーションを取得するように変更。

また、言語名ではなく出現頻度でソートするように変更しました。

途中で、mdfindでアプリケーションのファイルを抽出する処理を試していたら、サブフォルダ内のアプリケーションが出てこないという問題があり・・・開発マシンのSSD内のspotlightの検索辞書が壊れていたようで、再生成したら正常に動作するようになりました。mdfindの処理の落とし穴です。

マイナー言語(失礼!)をこまかくフォローしているのはGoogleアプリかと思っていたら、VLCでした。OSがサポートしていない言語用のローカライズを行っても意味はないのですが、ムービーの字幕表示などの関係でしょうか?

AppleScript名:アプリケーションのローカライズ分布を取得する v5
– Created 2014-12-23 by Takaaki Naganoya
– Changed 2014-12-24 by Shane Stanley
– Changed 2014-12-25 by Takaaki Naganoya

use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”

–mdfindで指定フォルダ以下にあるすべてのアプリケーションファイルを取得
set apPath1 to (path to applications folder) as string
set apList to getFileListWithSpotLight(“kMDItemContentType”, “com.apple.application-bundle”, apPath1) of me

set theCountedSet to current application’s NSCountedSet’s |set|()

–各アプリケーションのローカリゼーション情報を取得する
repeat with i in apList
  set j to contents of i
  
  
–指定アプリケーションのローカライズ言語を取得。重複を除去
  
set locList to getSpecifiedAppFilesLocalizationList(j) of me
  
–> {”de”, “English”, “fr”, “French”, “German”, “ja”, “Japanese”}
  
—-> {”German”, “English”, “French”,”Japanese”}
  
  
set locArray to (current application’s SMSFord’s Cocoaify:locList)
  
  
set theEnumerator to locArray’s objectEnumerator()
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
    (
theCountedSet’s addObject:aValue)
  end repeat
end repeat

–NSCountedSetをNSMutableArrayに変換
set theArray to current application’s NSMutableArray’s array()
set theEnumerator to theCountedSet’s objectEnumerator()

–NSMutableArrayから順次取り出して、NSArrayに対してDictionaryを追加
repeat
  set aValue to theEnumerator’s nextObject()
  
if aValue is missing value then exit repeat
  
theArray’s addObject:(current application’s NSDictionary’s dictionaryWithObjects:{aValue, (theCountedSet’s countForObject:aValue)} forKeys:{“theName”, “numberOfTimes”})
end repeat

–出現回数(numberOfTimes)で降順ソート
set theDesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“numberOfTimes” ascending:false
theArray’s sortUsingDescriptors:{theDesc}

return theArray as list

–> {{theName:”English”, numberOfTimes:733}, {theName:”Japanese”, numberOfTimes:404}, {theName:”French”, numberOfTimes:266}, {theName:”German”, numberOfTimes:265}, {theName:”Italian”, numberOfTimes:219}, {theName:”Spanish”, numberOfTimes:203}, {theName:”Dutch”, numberOfTimes:165}, {theName:”Chinese (China)”, numberOfTimes:149}, {theName:”Swedish”, numberOfTimes:133}, {theName:”Korean”, numberOfTimes:131}, {theName:”Russian”, numberOfTimes:129}, {theName:”Chinese (Taiwan)”, numberOfTimes:127}, {theName:”Portuguese”, numberOfTimes:124}, {theName:”Polish”, numberOfTimes:118}, {theName:”Danish”, numberOfTimes:117}, {theName:”Finnish”, numberOfTimes:110}, {theName:”Norwegian”, numberOfTimes:100}, {theName:”Czech”, numberOfTimes:92}, {theName:”Turkish”, numberOfTimes:90}, {theName:”Hungarian”, numberOfTimes:87}, {theName:”Greek”, numberOfTimes:76}, {theName:”Ukrainian”, numberOfTimes:75}, {theName:”Romanian”, numberOfTimes:74}, {theName:”Portuguese (Portugal)”, numberOfTimes:70}, {theName:”Slovak”, numberOfTimes:69}, {theName:”Catalan”, numberOfTimes:63}, {theName:”Croatian”, numberOfTimes:63}, {theName:”Arabic”, numberOfTimes:61}, {theName:”Thai”, numberOfTimes:61}, {theName:”Hebrew”, numberOfTimes:60}, {theName:”Indonesian”, numberOfTimes:58}, {theName:”Vietnamese”, numberOfTimes:57}, {theName:”Malay”, numberOfTimes:56}, {theName:”Spanish (Mexico)”, numberOfTimes:49}, {theName:”Base”, numberOfTimes:46}, {theName:”Portuguese (Brazil)”, numberOfTimes:22}, {theName:”Norwegian Bokmål”, numberOfTimes:21}, {theName:”Chinese (Simplified)”, numberOfTimes:19}, {theName:”Chinese”, numberOfTimes:14}, {theName:”English (United Kingdom)”, numberOfTimes:12}, {theName:”Bulgarian”, numberOfTimes:12}, {theName:”Chinese (Traditional)”, numberOfTimes:11}, {theName:”Latvian”, numberOfTimes:10}, {theName:”Lithuanian”, numberOfTimes:9}, {theName:”Slovenian”, numberOfTimes:9}, {theName:”Japanese (Japan)”, numberOfTimes:9}, {theName:”Czech (Czech Republic)”, numberOfTimes:9}, {theName:”Estonian”, numberOfTimes:8}, {theName:”Ukrainian (Ukraine)”, numberOfTimes:8}, {theName:”Spanish (Spain)”, numberOfTimes:7}, {theName:”Turkish (Turkey)”, numberOfTimes:7}, {theName:”Hungarian (Hungary)”, numberOfTimes:6}, {theName:”Danish (Denmark)”, numberOfTimes:6}, {theName:”Russian (Russia)”, numberOfTimes:6}, {theName:”French (XM)”, numberOfTimes:6}, {theName:”Swedish (Sweden)”, numberOfTimes:6}, {theName:”Serbian”, numberOfTimes:6}, {theName:”Norwegian Bokmål (Norway)”, numberOfTimes:6}, {theName:”Dutch (Netherlands)”, numberOfTimes:6}, {theName:”Persian”, numberOfTimes:5}, {theName:”Korean (South Korea)”, numberOfTimes:5}, {theName:”Finnish (Finland)”, numberOfTimes:5}, {theName:”Italian (Italy)”, numberOfTimes:5}, {theName:”German (Germany)”, numberOfTimes:5}, {theName:”French (Canada)”, numberOfTimes:5}, {theName:”French (France)”, numberOfTimes:5}, {theName:”Polish (Poland)”, numberOfTimes:5}, {theName:”Hindi”, numberOfTimes:5}, {theName:”English (United States)”, numberOfTimes:5}, {theName:”Hebrew (Israel)”, numberOfTimes:4}, {theName:”Arabic (United Arab Emirates)”, numberOfTimes:4}, {theName:”Spanish (Latin America)”, numberOfTimes:4}, {theName:”Romanian (Romania)”, numberOfTimes:4}, {theName:”Spanish (Namibia)”, numberOfTimes:4}, {theName:”Filipino”, numberOfTimes:4}, {theName:”Spanish (Laos)”, numberOfTimes:4}, {theName:”empty”, numberOfTimes:4}, {theName:”Greek (Greece)”, numberOfTimes:4}, {theName:”Telugu”, numberOfTimes:3}, {theName:”Malayalam”, numberOfTimes:3}, {theName:”Icelandic”, numberOfTimes:3}, {theName:”Kannada”, numberOfTimes:3}, {theName:”Galician”, numberOfTimes:3}, {theName:”Bengali”, numberOfTimes:3}, {theName:”Gujarati”, numberOfTimes:3}, {theName:”Marathi”, numberOfTimes:3}, {theName:”Tamil”, numberOfTimes:3}, {theName:”Belarusian”, numberOfTimes:3}, {theName:”Albanian”, numberOfTimes:2}, {theName:”Mongolian”, numberOfTimes:2}, {theName:”French (Morocco)”, numberOfTimes:2}, {theName:”Georgian”, numberOfTimes:2}, {theName:”Sinhala”, numberOfTimes:2}, {theName:”jp”, numberOfTimes:2}, {theName:”ua”, numberOfTimes:2}, {theName:”Amharic”, numberOfTimes:2}, {theName:”English (United Arab Emirates)”, numberOfTimes:2}, {theName:”Finnish (FL)”, numberOfTimes:2}, {theName:”Catalan (Spain)”, numberOfTimes:2}, {theName:”Basque”, numberOfTimes:2}, {theName:”English (Israel)”, numberOfTimes:2}, {theName:”Norwegian (NB)”, numberOfTimes:2}, {theName:”Oriya”, numberOfTimes:1}, {theName:”Punjabi”, numberOfTimes:1}, {theName:”Serbo-Croatian”, numberOfTimes:1}, {theName:”Walloon”, numberOfTimes:1}, {theName:”Corsican”, numberOfTimes:1}, {theName:”Sorani Kurdish”, numberOfTimes:1}, {theName:”Chinese (Hong Kong SAR China)”, numberOfTimes:1}, {theName:”Breton”, numberOfTimes:1}, {theName:”Cornish”, numberOfTimes:1}, {theName:”Chiga”, numberOfTimes:1}, {theName:”Aragonese”, numberOfTimes:1}, {theName:”Macedonian”, numberOfTimes:1}, {theName:”Japan”, numberOfTimes:1}, {theName:”Bosnian”, numberOfTimes:1}, {theName:”Ganda”, numberOfTimes:1}, {theName:”Tetum”, numberOfTimes:1}, {theName:”Welsh”, numberOfTimes:1}, {theName:”Armenian”, numberOfTimes:1}, {theName:”Kyrgyz”, numberOfTimes:1}, {theName:”Scottish Gaelic”, numberOfTimes:1}, {theName:”Afrikaans”, numberOfTimes:1}, {theName:”Zulu”, numberOfTimes:1}, {theName:”Swahili”, numberOfTimes:1}, {theName:”Burmese”, numberOfTimes:1}, {theName:”Chinese (Traditional, Taiwan)”, numberOfTimes:1}, {theName:”ct”, numberOfTimes:1}, {theName:”Tagalog”, numberOfTimes:1}, {theName:”Kazakh”, numberOfTimes:1}, {theName:”Bengali (India)”, numberOfTimes:1}, {theName:”Pashto”, numberOfTimes:1}, {theName:”Nepali”, numberOfTimes:1}, {theName:”Acoli”, numberOfTimes:1}, {theName:”Friulian”, numberOfTimes:1}, {theName:”Norwegian Nynorsk”, numberOfTimes:1}, {theName:”Asturian”, numberOfTimes:1}, {theName:”Thai (Thailand)”, numberOfTimes:1}, {theName:”Khmer”, numberOfTimes:1}, {theName:”Irish”, numberOfTimes:1}, {theName:”American”, numberOfTimes:1}, {theName:”Fulah”, numberOfTimes:1}, {theName:”Chinese (Traditional, Hong Kong SAR China)”, numberOfTimes:1}, {theName:”Occitan”, numberOfTimes:1}, {theName:”Interlingua”, numberOfTimes:1}, {theName:”Uzbek”, numberOfTimes:1}, {theName:”Azerbaijani”, numberOfTimes:1}}

–指定アプリケーションファイルの、指定Localeにおけるローカライズ言語リストを求める。重複を排除
on getSpecifiedAppFilesLocalizationList(anAppAlias as alias)
  
  
set aURL to (current application’s SMSFord’s URLFrom:anAppAlias)
  
set aBundle to current application’s NSBundle’s bundleWithURL:aURL
  
  
set theNSLocale to current application’s NSLocale’s localeWithLocaleIdentifier:“en” –Output Locale Name in English (en)
  
  
–Get Localization Info
  
set locList to aBundle’s localizations()
  
–> {”de”, “English”, “fr”, “French”, “German”, “ja”, “Japanese”}
  
set theEnumerator to locList’s objectEnumerator()
  
  
set theSet to current application’s NSMutableSet’s |set|()
  
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
    
set theName to (theNSLocale’s displayNameForKey:(current application’s NSLocaleIdentifier) value:aValue)
    
    
if theName is missing value then
      –”English”や”French”などは、missing valueが返ってくるので、”English”や”French”などをそのまま追加
      
theSet’s addObject:aValue
    else
      –”de”や”fr”などは、”German”や”French”が返ってくるので、それを追加
      
theSet’s addObject:theName
    end if
  end repeat
  
  
–NSCountedSetをNSMutableArrayに変換
  
set theArray to current application’s NSMutableArray’s array()
  
set theEnumerator to theSet’s objectEnumerator()
  
  
–NSMutableArrayから順次取り出して、NSArrayに対してDictionaryを追加
  
repeat
    set aValue to theEnumerator’s nextObject()
    
if aValue is missing value then exit repeat
    
theArray’s addObject:aValue
  end repeat
  
  
return theArray as list
  
end getSpecifiedAppFilesLocalizationList

–指定階層下で、指定メタデータが指定パラメータであるファイルを取得(alias list)
on getFileListWithSpotLight(aMetaDataItem as string, aParam as string, startDir as {alias, string})
  set sDirText to quoted form of POSIX path of startDir
  
set shellText to “/usr/bin/mdfind ’” & aMetaDataItem & ” == \”" & aParam & “\”’ -onlyin “ & sDirText
  
try
    set aRes to do shell script shellText
  on error
    return {}
  end try
  
set pList to paragraphs of aRes
  
set aList to {}
  
repeat with i in pList
    set aPath to POSIX file i
    
set aPath to aPath as alias
    
set the end of aList to aPath
  end repeat
  
return aList
end getFileListWithSpotLight

★Click Here to Open This Script 

2014/10/23 編集中のScript BundleあるいはApplet全体の行数をかぞえる

Script Editor(10.9まではAppleScriptエディタ。以下、エディタと略)で編集中のアプレットやバンドル形式のAppleScriptの、バンドル内に入れてあるサブScriptすべての行数をカウントするAppleScriptです。

バンドル形式のAppleScript、あるいはアプレットに入れてあるサブScript(共有機能を突っ込んであったり、個別に動作確認する必要があるモジュールなど)すべての行数をカウントしようとすると、わりとやっかいで面倒です。

scripts.png

そこで、専用のScriptを組んでカウントすることにしました。

実行すると、エディタ上でオープンしているAppleScriptの一覧が出るので、

asdiaog.png

任意のScript(バンドルScript、アプレット)を選択すると、バンドル内のすべてのScriptの名称と行数、さらに総合計の行数をTAB区切りテキストに(エディタの「結果」欄に)出力します。

エディタで直接バンドル内のAppleScriptを(AppleScript側から指令して)オープンさせるとエラーになるので、shellのosadecompileコマンドを使ってAppleScriptを(中間言語形式から)テキストに逆変換し、行数をカウントしています。

行数のカウントまでshell側で「wc -l」で行わせた方が速そうでしたが、AppleScript側でテキストを取得できれば、改行のみの行を除外するといった処理もできるので、今後の発展性を考慮してshell側でカウントしないようにしました。

ちなみに、バンドル形式のAppleScript、あるいはアプレットについては、バンドル内に入れたAppleScriptをエディタ上から直接オープンすると、変更したり保存したりする際にエディタが暴走してしまいます(10.9、10.10で確認)。バンドル内のAppleScriptを編集したい場合には、Finder上でバンドル内容を表示させたうえで、Finder側でバンドル内のAppleScriptをダブルクリックして編集するとエディタが暴走せずに編集、保存が可能です。

スクリプト名:編集中のScript BundleあるいはApplet全体の行数をかぞえる
set resList to {}
set resTotal to 0

–編集中のAppleScriptのうち、行数カウント対象を選択する
tell application "Script Editor"
  set dList to name of every document
  
  
set dRes to choose from list dList
  
if dRes = false then return –キャンセル時の対応
  
  
set ddRes to first item of dRes
  
  
tell document ddRes
    set aPath to path
  end tell
  
end tell

–バンドル中のScriptをすべて取得
set realPath to aPath & "/Contents/Resources/Scripts/"
set sRes to do shell script "ls " & (quoted form of realPath)
set sList to paragraphs of sRes

repeat with i in sList
  
  
set j to contents of i
  
set jj to realPath & j
  
  
–osadecompileコマンドで中間言語形式のAppleScriptをテキストに逆変換して行数をかぞえる
  
set tempAS to do shell script "/usr/bin/osadecompile " & quoted form of jj
  
set tempList to paragraphs of tempAS
  
set asCount to length of tempList –wc- lでカウントしてもいいが、本文の内容を取り出せておけたほうが便利
  
  
–出力リストに名称、行数のペアで追加
  
if j = "main.scpt" then
    set the end of resList to {ddRes & " (" & j & ")", asCount}
  else
    set the end of resList to {j, asCount}
  end if
  
  
–合計行数の算出
  
set resTotal to resTotal + asCount
  
end repeat

–総合計を出力リストの末尾に追加
set the end of resList to {"Total:", resTotal}

–2D ListをTAB区切りテキストに変換して結果に出力
set resText to retItemDelimedAndParagraphDelimedText(resList, tab, return) of me

–>
(*
"A1.scpt  264
A2.scpt  360
A3.scpt  358
A4.scpt  298
B1.scpt  298
B2.scpt  243
B3.scpt  294
B4.scpt  258

(中略)

設定ファイルから実行年月日&時のリストを展開.scpt  299
Total:  3570"
*)

–入れ子のリストを、アイテム間のデリミタとパラグラフ間のデリミタを指定してテキスト化
–というか、入れ子のリストをタブ区切りテキストにするのが目的
on retItemDelimedAndParagraphDelimedText(aList, itemDelim, paragraphDelim)
  set aText to ""
  
  
repeat with i in aList
    set aStr to retDelimedText(i, itemDelim) of me
    
set aText to aText & aStr & paragraphDelim
  end repeat
  
  
return aText
end retItemDelimedAndParagraphDelimedText

on retDelimedText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retDelimedText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/09/30 vim上でAppleScriptは書けないのか?

Twitter上での「こまったちゃんのつぶやき」(本人に悪意はないが、明らかに内容が間違っている)を拾っていると、新鮮な驚きに遭遇することがあります。

vim(unix上のテキストエディタ。元になったviはSunのビル・ジョイが作った)上でAppleScriptを書けないからどーのという内容でした。

では、実際にvim上でAppleScriptを書いてみましょう。

484d53c0-ad3a-4250-940c-fb2d176a1d6b.jpg

はい。ふつーに書けました。

f4ed6a94-228b-4244-b5fd-18dd6c8744ce.jpg

書いたテキストファイル「test.applescript」の内容をTerminal上でcatしてみて確認し、osascriptコマンドで実行。あらかじめFinder上で選択しておいたファイルの数を音声でかぞえます。

問題なく実行できました(10.9までは、osascript経由のAppleScript実行時には、display dialogとかchoose folderとかのユーザー操作を伴う命令は実行を拒否する仕様になっています。このため、display dialogを使っていません)。

ただ、AppleScript用語辞書の内容をTerminal上から参照できるわけではありませんし、アプリケーションの用語辞書の内容も参照できません。

ase1.jpg

さらに、オートインデントや省略表記を自動展開する機能(end tellやend ifなどを「end」だけ書いておけば構文確認(画面上に「コンパイル」と書いてあるが、一般的なコンパイルではなく実際には中間言語への翻訳。AppleScriptはインタプリタ型言語)時に自動展開してくれる、appと書いておくとapplicationと展開してくれる)も使えません。

構文要素ごとに色分け表示してくれる機能がないと、そのままではとても可読性がよくないです。

AppleScriptエディタ上で利用可能な、エディタ自体と他のツールを連携させたスクリプトアシスタントなど、超便利機能が一切使えないので、生産性はガタ落ちです。

できないわけではないけれど、やると不便。そういうことです。

2014/08/27 ログイン中のユーザーのPDFWriterのPDF出力フォルダを求める

仮想プリンタを提供し、印刷結果をPDFとして出力する「PDFWriter」がPDFを出力するフォルダのパスを求めるAppleScriptです。

ただし、正常に動作するためにはいくつかの前提条件をクリアする必要があります。

 (1)マシンにPDFWriterがインストールしてあること
 (2)少なくとも一度はPDFWriter経由でPDF出力したことがあること

(1)はともかく、インストール直後の一度もPDFWriter経由でPDF出力していない環境では、PDF出力フォルダが作成されていない可能性があります。

スクリプト名:ログイン中のユーザーのPDFWriterのPDF出力フォルダを求める
set aPath to retPDFWriterOutputFolder()
–> “/var/spool/pdfwriter/me/”

–ログイン中のユーザーのPDFWriterのPDF出力フォルダを求める
on retPDFWriterOutputFolder()
  
  
–ログイン中のユーザーアカウント名を取得する
  
tell application “System Events”
    set aProp to properties of current user
    
set aName to name of aProp
  end tell
  
  
–pdfwriterのPDF出力フォルダのパスを組み立てる
  
set printCuePath to “/var/spool/pdfwriter/” & aName & “/”
  
  
–PDF出力フォルダが存在するかどうか確認
  
try
    do shell script “cd “ & quoted form of printCuePath
  on error
    return false –パスが存在しない場合にはfalseを返す
  end try
  
  
return printCuePath
  
end retPDFWriterOutputFolder

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/23 Script Editorで最前面のアプリの用語辞書を表示する v3

AppleScriptエディタ/Script Editorで、最前面のアプリの用語辞書を表示するAppleScriptです。

バージョンアップして、最前面のアプリがAppleScript等のOSA(Open Scripting Architecture)言語によるScriptingに対応しているかどうかを判定したのちに、辞書のオープンを行います。

Script Menuに入れて、メニューから呼び出すことを前提としています。

前バージョンでは、とくに対象アプリケーションのScripting対応については調べていなかったため、非対応アプリを指定すると、Script Editorで対象アプリをバイナリモードでオープンしてしまうなどの問題があり、それに対処したものです。

本AppleScriptは、各アプリケーションのバンドル中にあるInfo.plistを走査してOSA対応の判定を行っていますが、これは「NSAppleScriptEnabled」のエントリがInfo.plist上に存在した場合、慣習的に「true」しか指定されていない(そもそも非対応である場合にはNSAppleScriptEnabledのエントリそのものを作らない)ことから、「NSAppleScriptEnabled」が入っていれば対応……という「手抜き判定」をやっています。

真剣に作るのであれば、NSAppleScriptEnabledのエントリを取得して属性値がどうなっているか判定すべきです。

スクリプト名:Script Editorで最前面のアプリの用語辞書を表示する v3
–最前面のプロセスのファイルシステム上の位置を取得してaliasに変換する
tell application “System Events”
  set frontProc to every process whose frontmost is true and visible is true
  
set aProc to contents of first item of frontProc
  
set aFile to file of aProc
  
set aBundleID to bundle identifier of aProc
end tell

set aFile to aFile as alias

–バンドルパッケージ中のInfo.plistファイルを走査してAppleScript対応かどうかを調べる
set aFilePosix to quoted form of POSIX path of aFile
set infoPath to aFilePosix & “Contents/Info.plist”
set aRec to extractInfoPlistAndFindString(infoPath, “NSAppleScriptEnabled”)

–スクリプト用語辞書をScript Editorでオープンする手順
if aRec = true then
  –OS X 10.10でScript Editor側からアプリをオープンしてもダメだったので、Finder側からScript Editorで指定アプリをオープンすることに
  
tell application “Finder”
    set apFile to (application file id “com.apple.scripteditor2″) as alias
    
open aFile using application file apFile
  end tell
else
  tell application id aBundleID
    display dialog “本アプリケーションは、各種OSA言語によるコントロールに対応していません。” buttons {“OK”} default button 1 with icon 2 with title “Scripting非対応”
  end tell
end if

–指定のInfoPlist(たぶん)をextractして指定文字列を含んでいるかチェック
on extractInfoPlistAndFindString(aPosix, findStr)
  
  
try
    set a to (do shell script “/usr/bin/plutil -p “ & aPosix)
  on error
    return 0 –エラー(指定のパスにファイルが存在しない)
  end try
  
  
set b to (a contains findStr)
  
return b
  
end extractInfoPlistAndFindString

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/22 AS対応、非対応のアプリ数をカウントする v2

Macのローカルに存在するアプリケーションをすべてリストアップし、AppleScript対応のもの、AppleScript非対応のもの、Info.plistが所定の位置にないものをカウントして返すAppleScriptです。

Finder経由でentire contentsを取得するものを試していたのですが……結果が返ってこない。

以前はもうちょっとentire contentsは「使える」気がしたのですが、実際に試した10.9上ではおかしな動作になっていました(ディスクのチェックが必要かも)。

そこで、mdfind経由でアプリケーションファイルを/Applications以下から取得するようにしてみたところ……数秒で結果が返ってきました。結局、mdfind(spotlight)系の(いつもの)ルーチンを使用することに。

「Info.plistが見つからない」とレポートされたアプリケーションの一覧を調べてみると、以前にWeb CGIとして作成した拡張子「.acgi」のAppleScriptのアプリとか、むか〜しのバンドル形式ではないフォーマットの(10.7以降では実行することができない)アプリケーションとか、あろうことかClassic形式のアプリケーションなどでした。

結局これを、アプリケーションのstringsファイルのローカライズ情報の取り出し(&データベースへの格納)のために使いたかった、という話で……けっこういろいろ寄り道してしまいました。

なお、プログラムリストの途中にシングルクォートが入っていたのでうまくWordPressに投稿できず(全角クォートとかに置き換える必要アリ?)、末尾の既出のサブルーチンはリストからは割愛してあります。

AppleScriptのHTML書き出し用AppleScriptを修正し、バックスラッシュとシングルクォートを全角文字に置き換えて出力するようにしました(記事が全部バックスラッシュになる怪奇現象に遭遇していましたが、これで解決)。

いつもどおり、プログラムリスト末尾のリンクをクリックすると、プログラム全体がAppleScriptエディタ/スクリプトエディタに転送されるようになっています。

スクリプト名:AS対応、非対応のアプリ数をカウントする v2
script spd
  property origList : {} –/Applications フォルダ以下のアプリケーションファイル一覧
  
  
property asEnable : {} –AS対応のアプリ一覧
  
property asDisable : {} –AS非対応のアプリ一覧
  
property infoNotPresent : {} –Info.plistが所定の場所に指定のファイル名で存在しないもの一覧
end script

set origList of spd to {}

set asEnable of spd to {}
set asDisable of spd to {}
set infoNotPresent of spd to {}

set apPath1 to (path to applications folder) as string

–mdfindで指定フォルダ以下にあるすべてのアプリケーションファイルを取得
set (origList of spd) to getFileListWithSpotLight(“kMDItemKind”, “アプリケーション”, apPath1) of me

repeat with i in (origList of spd)
  
  
set aFilePosix to quoted form of POSIX path of i
  
set infoPath to aFilePosix & “Contents/Info.plist”
  
  
set aRec to extractInfoPlistAndFindString(infoPath, “NSAppleScriptEnabled”)
  
  
if aRec = true then
    set the end of (asEnable of spd) to i
  else if aRec = false then
    set the end of (asDisable of spd) to i
  else
    set the end of (infoNotPresent of spd) to i
  end if
end repeat

return {length of (asEnable of spd), length of (asDisable of spd), length of (infoNotPresent of spd)}
–> {294, 580, 36}

–指定のInfoPlist(たぶん)をextractして指定文字列を含んでいるかチェック
on extractInfoPlistAndFindString(aPosix, findStr)
  
  
try
    set a to (do shell script “/usr/bin/plutil -p “ & aPosix)
  on error
    return 0 –エラー(指定のパスにファイルが存在しない)
  end try
  
  
set b to (a contains findStr)
  
return b
  
end extractInfoPlistAndFindString

–指定階層下で、指定メタデータが指定パラメータであるファイルを取得(alias list)
on getFileListWithSpotLight(aMetaDataItem, aParam, startDir)
  
  
set sDirText to quoted form of POSIX path of startDir
  
set shellText to “mdfind ’” & aMetaDataItem & ” == \”" & aParam & “\”’ -onlyin “ & sDirText
  
try
    set aRes to do shell script shellText
  on error
    return {}
  end try
  
set pList to paragraphs of aRes
  
set aList to {}
  
repeat with i in pList
    set aPath to POSIX file i
    
set aPath to aPath as alias
    
set the end of aList to aPath
  end repeat
  
return aList
end getFileListWithSpotLight

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/22 AS対応、非対応のアプリ数をカウントする

Macのローカルに存在するアプリケーションをすべてリストアップし、AppleScript対応のもの、AppleScript非対応のもの、Info.plistが所定の位置にないものをカウントして返すAppleScriptです。

下調べのために作ってみました。

すぐに「entire contentsで指定フォルダ以下のファイルをすべて取得してアプリのみ抽出するバージョン」に作り替えていますが……まだ、処理が返ってきません、、、

スクリプト名:AS対応、非対応のアプリ数をカウントする
script spd
  
  
property aList1 : {} –/Applications フォルダ以下のアプリケーションファイル一覧
  
property aList2 : {} –/Applications/Utilities フォルダ以下のアプリケーションファイル一覧
  
  
property bList : {} –aList1とaList2を連結
  
  
property asEnable : {} –AS対応のアプリ一覧
  
property asDisable : {} –AS非対応のアプリ一覧
  
property infoNotPresent : {} –Info.plistが所定の場所に指定のファイル名で存在しないもの一覧
  
end script

set aList1 of spd to {}
set aList2 of spd to {}

set bList of spd to {}

set asEnable of spd to {}
set asDisable of spd to {}
set infoNotPresent of spd to {}

set apPath1 to (path to applications folder) as string
set apPath2 to (path to utilities folder) as string

tell application “Finder”
  –/Applications Folder
  
tell folder apPath1
    set aList1 of spd to (every application file) as alias list
  end tell
  
  
–/Applications/Utilities Folder
  
tell folder apPath2
    set aList2 of spd to (every application file) as alias list
  end tell
end tell

set bList of spd to (contents of (aList1 of spd)) & (contents of (aList2 of spd))

repeat with i in (bList of spd)
  
  
set aFilePosix to quoted form of POSIX path of i
  
set infoPath to aFilePosix & “Contents/Info.plist”
  
  
set aRec to extractInfoPlistAndFindString(infoPath, “NSAppleScriptEnabled”)
  
  
if aRec = true then
    set the end of (asEnable of spd) to i
  else if aRec = false then
    set the end of (asDisable of spd) to i
  else
    set the end of (infoNotPresent of spd) to i
  end if
end repeat

return {length of (asEnable of spd), length of (asDisable of spd), length of (infoNotPresent of spd)}

–> {125, 235, 0}

–指定のInfoPlist(たぶん)をextractして指定文字列を含んでいるかチェック
on extractInfoPlistAndFindString(aPosix, findStr)
  
  
try
    set a to (do shell script “/usr/bin/plutil -p “ & aPosix)
  on error
    return 0 –エラー(指定のパスにファイルが存在しない)
  end try
  
  
set b to (a contains findStr)
  
return b
  
end extractInfoPlistAndFindString

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/22 指定のInfoPlist(たぶん)をextractして指定文字列を含んでいるかチェック

指定のInfo.plistがバイナリモードであってもextractして、指定の文字列を含んでいるかどうかチェックするAppleScriptです。

先日掲載した「Script Editorで最前面のアプリの用語辞書を表示する」を実戦配備したところ……AppleScript未対応のアプリケーションもオープンできてしまいました。Scripting未対応アプリをScript Editorでバイナリ状態でオープンしてしまったりして、おかしな状態に。

オープン対象のアプリケーションがScriptableかどうかをチェックしてから処理しよう……とも思ったのですが、実際にSystem Events経由で調べてみると、「iBooks」などの非対応アプリまでプロセス情報を確認すると「Accepts High Level Events」がtrueになっています。

……というわけで、実際に各アプリケーションバンドル内のInfo.plistファイルのエントリを調べて、NSAppleScriptEnabledが入っているか(ちょっとこのあたり乱暴)どうかを調べるAppleScriptを書いてみた次第です。

スクリプト名:指定のInfoPlist(たぶん)をextractして指定文字列を含んでいるかチェック
set infoPath to choose file with showing package contents
set aRec to extractInfoPlistAndFindString(infoPath, “NSAppleScriptEnabled”)

–指定のInfoPlist(たぶん)をextractして指定文字列を含んでいるかチェック
on extractInfoPlistAndFindString(aFile, findStr)
  
  
set aPosix to quoted form of POSIX path of aFile
  
set a to (do shell script “/usr/bin/plutil -p “ & aPosix)
  
  
set b to (a contains findStr)
  
return b
  
end extractInfoPlistAndFindString

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/07/14 指定のstringsファイルをparseして返す

全アプリケーションバンドル中の各Localizable.stringsのエントリをパースして、FileMaker Proにキー値と各国語訳語のデータベースを作成するAppleScriptを作り、運用しています。

bundle0.png

できあがったデータベースで、自分のアプリケーション上で使いたい単語を検索、繁体字でも簡体字でもフランス語でも、そのままほぼコピペでローカライズができる環境を目指して作っていました。

locdb.png

自分がローカルにインストールしているアプリケーション数は、けっこう多いので……処理に時間はかかったものの、一晩Macで処理させておけば、問題ありません。

ところが、Apple製のアプリケーションで、Localizable.stringsではなくさまざまなstringsファイルに分けて翻訳(ローカライズ)してあるケースが多々ありました。

また、データベースに取り出した文字データが文字化けしている箇所が散見され(バイナリ圧縮形式のplistをそのまま読んでしまった模様)、当初のAppleScriptを大幅に書き直す必要が出てきたのです。

処理を根本から見直して……/usr/bin/plutilコマンドを使って(バイナリ、文字形式を問わず)stringsファイルを文字化してからパースするようにしました。

本AppleScriptは、その.stringsファイルを読み込んでパースする部分だけを抜き出したものです。

bundle1.png

実行すると、stringsファイルを選択するよう促されるので、アプリケーションフォルダ内の何らかのアプリケーションの、Contents/Resources/フォルダ以下の適当なlprojフォルダ内のstringsファイルを選択してください。

stringsファイルのエントリをparseして2Dのリストに入れて返してくれます。外で使う予定のなかったプログラム(ほぼ書き捨て)だったので、「動くには動くけれど、判定とかが乱暴」な感じにはなっています。

スクリプト名:指定のstringsファイルをparseして返す
set aFile to choose file of type {"com.apple.xcode.strings-text"} with showing package contents
set aRes to parseStringsAs2DList(aFile)
–> {{"TOOLBAR_PREFS_LOGS", "ログファイル"}, {"INSTALL_BUTTON", "インストール"}, {"TOOLBAR_PREFS_GENERAL", "一般"}, {"TOOLBAR_SCANLOG_TOOLTIP", "スキャンログを開く"}, {"PREFS_LOGGING", "ログ設定"}, …..}

–指定のstringsファイルをparseして返す
on parseStringsAs2DList(aFile)
  
  
set aPosix to quoted form of POSIX path of aFile
  
  
set a to (do shell script "/usr/bin/plutil -p " & aPosix)
  
set aText to paragraphs 2 thru -2 of a –頭と末尾の"{", "}"をスキップする
  
set bText to retArrowText(aText, "") –(↑)でリストになっているので、この機会に不要な改行にともなう空きアイテムを削除
  
  
set nList to {}
  
  
repeat
    
    
set aPos to offset of "\"" in bText
    
if aPos = 0 then exit repeat
    
    
set bPos to offset of "\" => \"" in bText
    
if bPos = 0 then exit repeat
    
    
set word1 to text (aPos + 1) thru (bPos - 1) of bText
    
    
    
set bbText to text (bPos + 5 + 1) thru -1 of bText
    
set cPos to offset of "\"" in bbText
    
    
set word2 to text (bPos + 5 + 1) thru (bPos + 5 + cPos - 1) of bText
    
    
set the end of nList to {word1, word2}
    
    
–処理終了をえっらく投げやりな方法で検出(もうちょっとなんとかしたい)
    
try
      set cText to text (bPos + 5 + cPos + 2) thru -1 of bText
      
copy cText to bText
    on error
      exit repeat
    end try
    
  end repeat
  
  
return nList
  
end parseStringsAs2DList

–リストを任意のデリミタ付きでテキストに
on retArrowText(aList, aDelim)
  set aText to ""
  
set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set aText to aList as text
  
set AppleScript’s text item delimiters to curDelim
  
return aText
end retArrowText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/05/27 App Napのコントロール

Mavericksの新機能「App Nap」、ほかのウィンドウで隠れている場合にアプリのCPU利用率を抑えるもので、これをオン/オフにするAppleScript(ほとんどshell script)です。

MacBook ProでApp Napをオフにしたら、ファンが回りまくって大変だったので自分はデフォルトに戻しました。

スクリプト名:App Napを無効にする
do shell script "defaults write NSGlobalDomain NSAppSleepDisabled -bool YES"

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

スクリプト名:App Napを有効にする
do shell script "defaults write NSGlobalDomain NSAppSleepDisabled -bool NO"

tell application "System Events"
  restart
end tell

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/05/15 与えられた管理権限を持つユーザーアカウントのパスワードを試す

与えられた管理者ユーザーの名前とパスワードが妥当かどうかテストを行うAppleScriptです。

毒にも薬にもならないコマンド(pwd)を指定のユーザー名とパスワードで管理者権限実行してみて、エラーが発生したらパスワードが間違っている、というロジックです。妥当性評価コマンド自体が意外と存在していないので作っておきました。

本当は、このルーチンを含む超高機能ルーチンを作ったのですが、内容が長過ぎてWordPressに投稿したら記事が見えなくなってしまいました。残念。

スクリプト名:与えられた管理権限を持つユーザーアカウントのパスワードを試す
set rootUser to “hiyoko”
set rootPass to “xxxxx”

set pRes to verifyAdminUserPassword(rootUser, rootPass) of me
–> false

–与えられた管理権限を持つユーザーアカウントのパスワードを試す
on verifyAdminUserPassword(rootUser, rootPass)
  try
    do shell script “/bin/pwd” user name rootUser password rootPass with administrator privileges
    
return true
  on error
    return false
  end try
end verifyAdminUserPassword

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に

2014/05/13 選択中のフォルダ内のすべてのファイルの作成日、変更日をcurrent dateに変更 v2

Finder上で選択中のフォルダ内のすべてのファイル/フォルダの作成日、変更日を現在時刻に変更するAppleScriptの、OS X 10.9対応版です。

実行のためには、Xcodeのインストールが必要です(/usr/bin/SetFileコマンド)。

currentdater.png

Script Menuに入れて、サンプルのXcodeプロジェクトの作成日/修正日の日付をまとめて変更するために作ったものです。

スクリプト名:選択中のフォルダ内のすべてのファイルの作成日、変更日をcurrent dateに変更 v2
set aCurDate to current date
set aDateStr to makeMMDDYYYYhhmmssStr(aCurDate) of me

tell application “Finder”
  set aSel to selection as alias list
  
if aSel = {} or aSel is equal to missing value then
    display dialog “何も選択されていません。” buttons {“OK”} default button 1
    
return
  end if
end tell

repeat with i in aSel
  
  
set j to contents of i
  
set aKind to detectFolder(j) of me
  
  
–選択中のアイテムがフォルダの場合にはその中のファイル一覧を取得
  
set fList to {}
  
  
if aKind = true then
    tell application “Finder”
      tell folder (j as string)
        set fList to entire contents as alias list
      end tell
    end tell
  else
    –選択中のアイテムがファイルの場合にはそのままリストに入れる
    
set fList to {j}
  end if
  
  

  
repeat with i in fList
    set j to contents of i
    
set aFres to detectFolder(i) of me
    
changeCreationDate(j, aDateStr) of me
  end repeat
  
end repeat

–aliasがFolderかどうか判定
on detectFolder(aSelFol)
  set aInfo to info for aSelFol as alias
  
tell application “Finder”
    try
      set aFol to kind of aInfo
    on error
      return false
    end try
  end tell
  
  
return (aFol = “フォルダ”) –”Folder” in Japanese, change here to each localized string
end detectFolder

–作成日と修正日を変更する
on changeCreationDate(aFile, aDateStr)
  set bP to POSIX path of aFile
  
  
try
    do shell script “/usr/bin/SetFile -d “ & quoted form of aDateStr & ” “ & quoted form of bP –作成日
    
do shell script “/usr/bin/SetFile -m “ & quoted form of aDateStr & ” “ & quoted form of bP –修正日
  end try
  
end changeCreationDate

–DateオブジェクトからMM/DD/YYYY hh:mm:ssの形式の文字列を返す
on makeMMDDYYYYhhmmssStr(aDate)
  –Dateオブジェクトから各要素を取り出す
  
set yStr to (year of aDate) as string
  
set mStr to (month of aDate as number) as string
  
set dStr to (day of aDate) as string
  
set hhStr to (hours of aDate) as string
  
set mmStr to (minutes of aDate) as string
  
set ssStr to (seconds of aDate) as string
  
  
–桁数を合わせる
  
set y2Str to retZeroPaddingText(yStr, 4) of me
  
set m2Str to retZeroPaddingText(mStr, 2) of me
  
set d2Str to retZeroPaddingText(dStr, 2) of me
  
set hh2Str to retZeroPaddingText(hhStr, 2) of me
  
set mm2Str to retZeroPaddingText(mmStr, 2) of me
  
set ss2Str to retZeroPaddingText(ssStr, 2) of me
  
  
return (m2Str & “/” & d2Str & “/” & y2Str & ” “ & hh2Str & “:” & mm2Str & “:” & ss2Str)
end makeMMDDYYYYhhmmssStr

–数値にゼロパディングしたテキストを返す
on retZeroPaddingText(aNum, aLen)
  set tText to (“0000000000″ & aNum as text)
  
set tCount to length of tText
  
set resText to text (tCount - aLen + 1) thru tCount of tText
  
return resText
end retZeroPaddingText

▼新規書類に ▼カーソル位置に ▼ドキュメント末尾に