Archive for the 'Finder' Category

2017/03/13 Finderの最前面のウィンドウで選択中のアイテムと非選択アイテムを切り替える

Finderの最前面のウィンドウ中で選択中のアイテムと選択対象外のアイテムを切り替えるAppleScriptです。

finder_anime2.gif

どういう場面において便利なのかは不明ですが、、、、

AppleScript名:Finderの最前面のウィンドウで選択中のアイテムと非選択アイテムを切り替える
– Created 2017-03-12 by Takaaki Naganoya
– 2017 Piyomaru Software
–http://piyocast.com/as/archives/4526
tell application "Finder"
  if (count every window) = 0 then return
  
set aSel to selection as alias list
  
  
tell window 1
    set aList to (every file) as alias list
  end tell
  
  
set newSel to {}
  
repeat with i in aList
    set j to contents of i
    
if j is not in aSel then
      set the end of newSel to j
    end if
  end repeat
  
  
set selection to newSel
end tell

★Click Here to Open This Script 

2016/10/31 指定ファイルをFinderで選択表示

指定のファイルをFinder上で選択状態で表示するAppleScriptです。

何か処理結果をファイルに書き出したような場合、どのファイルに出力したかを明示的に表現するために、Finder上で新規ウィンドウを作成して対象ファイルを選択状態にすることはよくあります。

そのためのAppleScriptで、Pure AppleScript版とCocoaの機能を用いたAppleScriptObjC版です。

見比べてみて、このぐらいの素朴な処理&用途ではASOCを使う意義が見出せないですね。

AppleScript名:指定ファイルをFinderで選択表示_pure_as
– Created 2016-10-31 by Takaaki Naganoya
– 2016 Piyomaru Software
–http://piyocast.com/as/archives/4297

set aFile to choose file
tell application “Finder”
  activate
  
reveal aFile
end tell

★Click Here to Open This Script 

AppleScript名:指定ファイルをFinderで選択表示_asoc
– Created 2016-10-31 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”
–http://piyocast.com/as/archives/4297

set aFile to POSIX path of (choose file)
set pathStr to current application’s NSString’s stringWithString:aFile
set parentPath to pathStr’s stringByDeletingLastPathComponent()
set aRes to current application’s NSWorkspace’s sharedWorkspace()’s selectFile:pathStr inFileViewerRootedAtPath:parentPath

★Click Here to Open This Script 

2016/10/05 SDカードを検出

マウント中のドライブのマウントポイント(例:/Volumes/ドライブ名)を指定すると、当該ドライブがSDカードかどうかを判定するAppleScriptです。

system_profilerコマンドを呼び出して詳細な情報を取得して判定するようにして、手元にある2枚のSDカードはこれで判定できています。MacBook Pro Retina 2012の内蔵SDカードリーダー、およびUSB接続のSDカードリーダーの両方で判定できることを確認しています。

system_profilerの実行結果は、

mountedsd1.jpg

MacBook Pro Retina内蔵SDカードリーダーに入れたSDXCカード「JVCCAM_SD」
-> {writable:”yes”, _name:”JVCCAM_SD”, ignore_ownership:”yes”, file_system:”MS-DOS FAT32″, size_in_bytes:3.3179041792E+10, bsd_name:”disk3s1″, free_space_in_bytes:2.0819673088E+10, mount_point:”/Volumes/JVCCAM_SD”, physical_drive:{is_internal_disk:”yes”, device_name:”Built In SDXC Reader”, protocol:”Secure Digital”, media_name:”Apple SDXC Reader Media”, partition_map_type:”master_boot_record_partition_map_type”}}

USB接続SDカードリーダーに入れたSDカード「RICOHDCX」
–> {writable:”yes”, _name:”RICOHDCX”, ignore_ownership:”yes”, file_system:”MS-DOS FAT32″, volume_uuid:”3BD2F468-5B42-327C-AB96-2812A02E7126″, size_in_bytes:7.939817472E+9, bsd_name:”disk4s1″, free_space_in_bytes:5.415960576E+9, mount_point:”/Volumes/RICOHDCX”, physical_drive:{is_internal_disk:”no”, device_name:”SD Transcend”, protocol:”USB”, media_name:”TS-RDF5 SD Transcend Media”, partition_map_type:”master_boot_record_partition_map_type”}}

mountedsd2.jpg

MacBook Pro Retina内蔵SDカードリーダーに入れたSDカード「RICOHDCX」
–> {writable:”yes”, _name:”RICOHDCX”, ignore_ownership:”yes”, file_system:”MS-DOS FAT32″, volume_uuid:”3BD2F468-5B42-327C-AB96-2812A02E7126″, size_in_bytes:7.939817472E+9, bsd_name:”disk3s1″, free_space_in_bytes:5.415960576E+9, mount_point:”/Volumes/RICOHDCX”, physical_drive:{is_internal_disk:”yes”, device_name:”Built In SDXC Reader”, protocol:”Secure Digital”, media_name:”Apple SDXC Reader Media”, partition_map_type:”master_boot_record_partition_map_type”}}

USB接続SDカードリーダーに入れたSDXCカード「JVCCAM_SD」
–> {writable:”yes”, _name:”JVCCAM_SD”, ignore_ownership:”yes”, file_system:”MS-DOS FAT32″, size_in_bytes:3.3179041792E+10, bsd_name:”disk4s1″, free_space_in_bytes:2.0819673088E+10, mount_point:”/Volumes/JVCCAM_SD”, physical_drive:{is_internal_disk:”no”, device_name:”SD Transcend”, protocol:”USB”, media_name:”TS-RDF5 SD Transcend Media”, partition_map_type:”master_boot_record_partition_map_type”}}

となっており、device_nameとmedia_nameを単語ごとにリスト化し、「SD」「SDHC」「SDXC」の単語が入っているかどうかを判定しています。

同一名称のSDカードが複数枚同時にマウントされた場合の挙動については検証していないため、そういうケースには対応しきれていないと思われます。ご注意ください。

AppleScript名:SDカードを検出
– Created 2016-10-04 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4251

tell application “Finder”
  set driveList to every disk whose format is (MSDOS format) and ejectable is true and startup is false
  
  repeat with i in driveList
    set myDisk to disk of (first item of i)
    
set myMountPoint to POSIX path of (myDisk as alias)
    
–> “/Volumes/JVCCAM_SD/”
    
–> “/Volumes/RICOHDCX/”
    
set sdRes to detectSDCard(myMountPoint) of me
    
–> true –SD Card, false –Not SD Card
  end repeat
end tell

on detectSDCard(myMountPoint as string)
  
  set resData to runCommandString(“system_profiler -xml SPStorageDataType”) of me
  
set aaDict to (readPlistFromStr(resData) of me) as list
  
set aDictList to (_items of first item of aaDict)
  
  repeat with i in aDictList
    set j to contents of i
    
    set aMountPoint to (mount_point of j) as string
    
–> “/Volumes/JVCCAM_SD”
    
–> “/Volumes/RICOHDCX”
    
    if aMountPoint is not equal to “/” then
      if ((aMountPoint & “/”) is equal to myMountPoint) then
        set aDevName to words of (device_name of physical_drive of j)
        
set aMediaName to words of (media_name of physical_drive of j)
        
        –SD/SDHC/SDXCのカード検出
        
set aDevF to (“SD” is in aDevName) or (“SDHC” is in aDevName) or (“SDXC” is in aDevName)
        
set aMediaF to (“SD” is in aMediaName) or (“SDHC” is in aMediaName) or (“SDXC” is in aMediaName)
        
        if (aDevF and aMediaF) then return true
      end if
    end if
  end repeat
  
  return false
end detectSDCard

–文字列で与えたシェルコマンドを実行する
on runCommandString(commandStr as string)
  set aPipe to current application’s NSPipe’s pipe()
  
set aTask to current application’s NSTask’s alloc()’s init()
  
aTask’s setLaunchPath:“/bin/sh”
  
aTask’s setArguments:{“-c”, current application’s NSString’s stringWithFormat_(“%@”, commandStr)}
  
aTask’s setStandardOutput:aPipe
  
set aFile to aPipe’s fileHandleForReading()
  
aTask’s |launch|()
  
return current application’s NSString’s alloc()’s initWithData:(aFile’s readDataToEndOfFile()) encoding:(current application’s NSUTF8StringEncoding)
end runCommandString

–stringのplistを読み込んでRecordに
on readPlistFromStr(theString)
  set aSource to current application’s NSString’s stringWithString:theString
  
set pListData to aSource’s dataUsingEncoding:(current application’s NSUTF8StringEncoding)
  
set aPlist to current application’s NSPropertyListSerialization’s propertyListFromData:pListData mutabilityOption:(current application’s NSPropertyListImmutable) |format|:(current application’s NSPropertyListFormat) errorDescription:(missing value)
  
return aPlist
end readPlistFromStr

★Click Here to Open This Script 

2016/10/04 Finderの最前面のフォルダを取得して、choose folderの始点フォルダに指定する

Finderの最前面のWindowで表示しているフォルダ(target)を取得して、後続のchoose folderコマンドで表示するデフォルトフォルダに指定するAppleScriptです。

targwin1_resized.png
▲最前面のWindowの内容

targwin2_resized.png
▲最前面のWindowの対象フォルダ(target)を取得してchoose folder

こういうのは、技術的にすごいとかどーのとかいうことは全然なくて、「おもてなし度が向上する」ワザ。過剰にやりすぎると嫌われることもあるので、用法・容量を守って過剰に使いすぎない程度に使ってみるといいのでしょう。

既存のPDFに対して指定フォルダ内のJPEG画像を末尾に追加するAppleScriptを書いたときに、「指定フォルダ」が最前面にあるのになんでこれを毎回指定しないとダメなんだろうか、と思って作ってみたものです。

AppleScript名:Finderの最前面のフォルダを取得して、choose folderの始点フォルダに指定する
– Created 2016-10-04 by Takaaki Naganoya
– 2016 Piyomaru Software
–http://piyocast.com/as/archives/4244

set targAlias to retFrontFinderWindowsTargetIfExits(path to desktop) of me
set aFol to choose folder default location targAlias

on retFrontFinderWindowsTargetIfExits(aDefaultLocation)
  tell application “Finder”
    set wCount to count every window
    
if wCount 1 then
      tell front window
        set aTarg to target as alias
      end tell
      
return aTarg
    else
      return aDefaultLocation
    end if
  end tell
end retFrontFinderWindowsTargetIfExits

★Click Here to Open This Script 

2016/07/28 Bookフォルダリネーム

書籍の原稿管理用のAppleScriptです。原稿は章ごとにフォルダ分けしており、

 9999 フォルダ名あるいはファイル名

といったように、仮想ノンブルを前に付けています。この仮想ノンブルで前後関係を制御しており、基本的に数字の大小だけが重要です。

whole.png

最後に1冊分PDFにまとめてビルドするAppleScriptで、書き出し対象のフォルダ以下のMarkdownファイルとPagesのファイルをピックアップし、ファイル名でソート。ソート順は仮想ノンブルによってコントロールされることになります。

Finderの並べ替えを使っているので、シンプルでわかりやすく、使い勝手もよいのですが……ただひとつ難点が。

途中にコンテンツを挿入したい場合にも仮想ノンブルでコントロールしつつ、途中に入るように操作するのですが……場合によってはフォルダおよび書類の仮想ノンブル部分だけリネームする必要が出てきます。

とくに、目下改定作業中の「AppleScript最新リファレンス」のコマンドリファレンス部分は、初版から大幅に改定・補充を行っているため、ひんぱんにリネームが発生して大変です(ーー;;

そこで、こんなScriptを組んでリネーム作業だけ自動化してみました。

Finder上でフォルダを選択して本Scriptを実行すると、選択中のフォルダ名から仮想ノンブルの番号を取得し、

before2.png

内包するフォルダに入っているファイルについても、すべて仮想ノンブル部分を書き換えます。

after2.png

AppleScript名:Bookフォルダリネーム
– Created 2016-07-28 by Takaaki Naganoya
– 2016 Piyomaru Software
use AppleScript version “2.4″
use framework “Foundation”
use scripting additions
# http://piyocast.com/as/archives/4177

set aStep to 10

tell application “Finder”
  set aSel to (selection as alias list)
end tell
if aSel = {} or aSel = “” then return
set aFol to first item of aSel

tell application “Finder”
  –選択中のフォルダの名称を取得
  
set aName to name of aFol
  
  
–選択中のフォルダに入っている書類を取得
  
tell folder (aFol as string)
    set fList to name of every file as alias list
  end tell
end tell

set {startNumStr, folderNameStr} to parseNumAndString(aName) of me
set startNum to startNumStr as integer

set aRes to sort1DListOrder(fList, true) of me –昇順でファイル名をソート

set aFolStr to aFol as string
set aCount to startNumStr
tell application “Finder”
  repeat with i in aRes
    set anAlias to (aFolStr & (i as string)) as alias
    
set tmpName to name of anAlias
    
    
set {curNum, curName} to parseNumAndString(tmpName) of me
    
set newName to (retZeroPaddingText(aCount, length of curNum) of me) & ” “ & curName
    
    
set name of anAlias to newName
    
    
set aCount to aCount + aStep
  end repeat
end tell

–文字列から先頭にあるとおぼしき数値と、スペースで区切られた後続の文字列を分離する
on parseNumAndString(aName)
  set aOffset to offset of ” “ in aName
  
if aOffset = 0 then error “Illigal Format”
  
set aNum to text 1 thru (aOffset - 1) of aName
  
set aText to text (aOffset + 1) thru -1 of aName
  
return {aNum, aText}
end parseNumAndString

–1D Listをsort / ascOrderがtrueだと昇順ソート、falseだと降順ソート
on sort1DListOrder(theList, aBool)
  set aDdesc to current application’s NSSortDescriptor’s sortDescriptorWithKey:“self” ascending:aBool selector:“localizedCaseInsensitiveCompare:”
  
set theArray to current application’s NSArray’s arrayWithArray:theList
  
return (theArray’s sortedArrayUsingDescriptors:{aDdesc}) as list
end sort1DListOrder

on retZeroPaddingText(aNum as integer, aDigitNum as integer)
  if aNum > (((10 ^ aDigitNum) as integer) - 1) then return “” –Range Check
  
set aFormatter to current application’s NSNumberFormatter’s alloc()’s init()
  
aFormatter’s setUsesGroupingSeparator:false
  
aFormatter’s setAllowsFloats:false
  
aFormatter’s setMaximumIntegerDigits:aDigitNum
  
aFormatter’s setMinimumIntegerDigits:aDigitNum
  
aFormatter’s setPaddingCharacter:“0″
  
set aStr to aFormatter’s stringFromNumber:(current application’s NSNumber’s numberWithFloat:aNum)
  
return aStr as string
end retZeroPaddingText

★Click Here to Open This Script 

2015/09/08 Dockアイコンをバウンドさせる

Cocoaの機能を用いて、DockのアイコンをバウンドさせるAppleScriptです。

実行中のアプリケーション(Script EditorやAppletを前提)が最前面に来ていない場合にDockのアイコンをバウンドさせます。

Finderを最前面に出しているのは動作確認のためで(最前面にScript EditorがいるとDockアイコンがバウンドしない)、それ以上でもそれ以下でもありません。

AppleScript名:ASOCでDockアイコンをバウンドさせる
– Created 2015-09-08 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

tell application “Finder” to activate –Script Editor/ASObjC Explorer 4を背面に

set anApp to current application’s NSApplication’s sharedApplication()
anApp’s requestUserAttention:(current application’s NSCriticalRequest)

★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/07/23 ASOCでフォルダの連続作成1万個

ASOCでCocoaの機能を用いたフォルダ作成のテストを行いました。比較用にCocoaの機能を用いずにFinder経由で作成したものと、do shell script経由でシェルコマンドの機能を用いたものを用意して比較。

filegraph1.png

Cocoa経由で作成したものが非常に高速(Finder経由の7倍速ぐらい)ということが分かりました。ただし、テスト所要時間が実行するたびに変わり、ブレがあるのが特徴です(Finder経由で作成したときにはあまり見られない現象)。

テストはMacBook Pro Retina 2012 (Core i7 2.6GHz)、OS X 10.10.5上で実施。もちろん、HDDではなくSSDを使っていればこその速度です。

ASOCのテスト1は常識的なフォルダ作成のルーチンを作って呼び出したもの、テスト2は速度をかせぐために「連番のフォルダを作成する」という機能のかたまりを作成して、サブルーチンにはしなかったものです。ねらいどおり、若干後者の方が高速ですが・・・逆に、NSFileManager’s defaultManager() を1万回呼び出して無駄にオブジェクトを生成しても(テスト1)たいしたオーバーヘッドにならないんだなーということが体感的によく分かりました。

念のため、do shell scirpt経由でのフォルダ作成をためしてみたところ、予想外に時間がかかりました。do shell scirptコマンドによるシェルコマンド呼び出しのオーバーヘッドが大きいことが分かります(シェルコマンドが遅いのではなく、呼び出しのためのオーバーヘッドが大きい。シェル側からosascriptコマンドでAppleScriptを呼び出すと同様の現象が起こる)。

あまりにdo shell script使用バージョンが遅かったので、「mkdir -p」ではなく「mkdir」で実行してみたものの、大差はありませんでした。

Shane Stanleyが「do shell scriptコマンドなんか使うのやめようよ」(Cocoaの機能を呼び出したほうがいいぞ)と言っていた理由がよ〜くわかりました。

AppleScript名:ASOCでフォルダ作成テスト1
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–計時用
set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

repeat with i from 1 to 10000
  set aDirStr to “Desktop/test/” & (i as string)
  
set aRes to makeDirUnderHome(aDirStr) of me
end repeat

–計時用
set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat
–> 5.814414978027 (MacBook Pro Retina 2012, Core i7 2.6GHz)

on makeDirUnderHome(dirStr)
  
  
set homeDir to current application’s NSHomeDirectory()
  
set dirPath to homeDir’s stringByAppendingPathComponent:dirStr
  
set fileManager to current application’s NSFileManager’s defaultManager()
  
  
  
–Sample with continuation mark (¬) , similar to Objective-C format
  
set aRes to fileManager’s createDirectoryAtPath:dirPath ¬
    withIntermediateDirectories:true ¬
    
attributes:(missing value) ¬
    
|error|:(reference)
  
  
–Sample without continuation mark (¬)
  
–set aRes to fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
  
  
copy aRes to {aFlag, aError}
  
return aFlag as boolean
  
end makeDirUnderHome

★Click Here to Open This Script 

AppleScript名:ASOCでフォルダ作成テスト2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–計時用
set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

set homeDir to current application’s NSHomeDirectory()
set fileManager to current application’s NSFileManager’s defaultManager()

repeat with i from 1 to 10000
  
  
set aDirText to “Desktop/test/” & (i as string)
  
set dirPath to (homeDir’s stringByAppendingPathComponent:aDirText)
  
  
set aRes to (fileManager’s createDirectoryAtPath:dirPath withIntermediateDirectories:true attributes:(missing value) |error|:(reference))
  
end repeat

–計時用
set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat
–> 4.124059021473 (MacBook Pro Retina 2012, Core i7 2.6GHz)

★Click Here to Open This Script 

AppleScript名:ASで(Finder経由で)フォルダ作成テスト(比較用)
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–計時用
set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

set dtPath to path to desktop
set dtPathStr to dtPath as string
set tFolStr to dtPathStr & “test:”

tell application “Finder”
  
  
tell folder dtPath
    if (exists of folder “test”) = false then
      (make new folder with properties {name:“test”})
    end if
  end tell
  
  
repeat with i from 1 to 10000
    make new folder with properties {name:(i as string)} at folder tFolStr
  end repeat
  
end tell

–計時用
set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat
–> 37.555700004101

★Click Here to Open This Script 

AppleScript名:ASでフォルダ作成テスト(比較用2)
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–計時用
set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

set dtPath to path to desktop
set dtPathStr to dtPath as string
set tFolStr to dtPathStr & “test:”
set tFolPosix to POSIX path of tFolStr

repeat with i from 1 to 10000
  set tPath to tFolPosix & (i as string)
  
do shell script “mkdir -p “ & tPath
end repeat

–計時用
set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat
–> 272.857131958008

★Click Here to Open This Script 

AppleScript名:ASでフォルダ作成テスト(比較用3)
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”

–計時用
set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()

set dtPath to path to desktop
set dtPathStr to dtPath as string
set tFolStr to dtPathStr & “test:”
set tFolPosix to POSIX path of tFolStr

do shell script “mkdir -p “ & tFolPosix

repeat with i from 1 to 10000
  set tPath to tFolPosix & (i as string)
  
do shell script “mkdir “ & tPath
end repeat

–計時用
set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate()
set c1Dat to b1Dat - a1Dat
–> 283.687083005905

★Click Here to Open This Script 

2015/07/17 Finderで選択中の戦場の絆のリプレイムービーのファイル名を取得して対戦人数を集計する

YouTubeからダウンロードした「戦場の絆」のリプレイムービー(複数)をFinder上で選択しておくと、ファイル名を取得してファイル名に記載されている「4VS4」などの文字列をもとに、各対戦人数(1VS1〜8VS8)の該当個数をカウントするAppleScriptです。

scrn1.png

scrn3.png

res.png

Finder上のファイルを処理するときに、

Finder上で選択中のファイルを取得する
choose fileコマンドで選択する
choose folderコマンドでフォルダを選択してその中に入っているファイルを処理する

といったあたりが定番です。ドラッグ&ドロップを受け付ける「ドロップレット」にすることも可能ですが、ドロップレットにするとデバッグが非常に困難になるため、最初はこのような形態のScriptにすることを強く推奨します。

AppleScript名:Finderで選択中の戦場の絆のリプレイムービーのファイル名を取得して対戦人数を集計する
tell application “Finder”
  set aSel to selection as alias list –Finder上で選択中のファイルを取得する定番の書き方
end tell

if aSel = {} then return –何もFinder上で選ばれていなかった場合

set outStr to “”

repeat with i from 1 to 8
  set aVSstr to makeVSstr(i) of me
  
set aCount to 0
  
  
repeat with ii in aSel
    tell application “System Events”
      set aName to name of ii
      
if aVSstr is in aName then
        set aCount to aCount + 1
      end if
    end tell
  end repeat
  
  
if aCount > 0 then
    set outStr to outStr & aVSstr & “:” & (aCount as string) & return
  end if
  
end repeat

outStr –「結果」への結果出力

– Sub-routine: 4 –> “4VS4″
on makeVSstr(aNum)
  set aNumStr to aNum as string
  
return aNumStr & “VS” & aNumStr
end makeVSstr

★Click Here to Open This Script 

2015/03/25 公開添削:サーバー上のファイル権限をローカルで書き換えて書き戻し

This is a special correction of my friend’s AppleScript. He is a beginner of AppleScript. So, I confused by his script and struggled with it.

At first, I didn’t understand original script at all. After several mail transactions, I understood his thought.

step1: Re-confirm the specification. Your spec is only in your brain. I don’t understand at all
step2: Where is comments?
step3: Make blank line to separate processing blocks
step4: Don’t make droplet. It is hard to debug!!
step5: The name of variables are important
step6: Mis-matching sub-routine’s spec
step7: Change the name of sub-routine


知り合いが「AppleScriptのバグが抜けない」と言っていたので、バーターで(未公開ソフトの評価)バグ抜き&公開指導をしてみることにしました。

「サーバ管理権限のないマシンから得意先が投げてきたアクセス権のおかしいファイルをフォルダごとローカルにコピーしてアクセス権を変更して元の階層に上書き、という内容のもと、ASを手習い中であります。

(Finderの)「内包している項目に適用」に相当する命令が見つからずループ仕立てにしてみています。まだまだAS自体つかめておらず、ほとんど拾ったコードのつぎはぎですが。」

▼Danger!!! Never Execute This Script.

AppleScript名:Original Script
【コメント】 Don’t Execute!!! This Script is incomplete!!!
————-
on open fileList
  tell application “Finder”
    set myDir to (parent of item 1 of fileList)
    
set aList to duplicate fileList to desktop
    
repeat with aItem in aList
      DiveFolder(aItem) of me
    end repeat
    
–move aList to myDir
    
–[true]
    
–delete aList
  end tell
end open

on DiveFolder(thePath)
  tell application “Finder”
    set theFiles to every file of thePath
    
repeat with aFile in theFiles
      set owner privileges of aFile to read write
      
set everyones privileges of aFile to read only
    end repeat
    
set theFolders to every folder of thePath
    
repeat with aFolder in theFolders
      DiveFolder(aFolder) of me
    end repeat
  end tell
end DiveFolder
————-

★Click Here to Open This Script 

チェック項目1:仕様がよくわからない

最初、すでにローカルにコピーしておいたものをScriptで処理するのかと思っていたのですが、違うとのこと。何度かメールをやりとりして、ようやく理解しました。

チェック項目2:コメントがない

自分の書いたScriptでも1日もたつと内容を忘れてしまいがちです。他人が書いたものだと、暗号解読に近いものになります。

コメントがないと、どういう意図のもとに書かれたのかが分からず、とても読みにくいです。

どういう意図で処理をしているのか、適度にコメントを入れましょう(サンプルでは、かなり多めに=過剰に入れています)。

チェック項目3:空行がなくて読みにくい

個人の趣味の問題ではありますが、処理上のまとまりが途切れたところで空行を入れると読みやすくなり、処理の意図が通じやすくなります。書き換え前後の比較を行うと一目瞭然です。

チェック項目4:Dropletをいきなり作るのはダメ

初心者にありがちな「実力不相応な高い到達点にいきなり行こうとする」パターンです。

Script Editorにはデバッグのための簡単な機能(ログ表示機能)がありますが、Dropletはアプリケーション形式でしか機能せず、アプリケーション形式で動かすとログを表示させたり動作内容を確認することができません。最後の最後でドロップレットにするとしても、最初はもっと低い到達点から、確実に動作することを確認しながら書き始めるべきです。

最初は、choose file/choose folderで選択するのがベスト。もうちょっとスマートにしたいなら、Finderのselectionを取得。Dropletにするのは、すべてが完成したあとの話です。

それでも、最初からDropletを作りたい場合にはScript Debuggerを買いましょう。Dropletもデバッグできます。初心者にこそ、Script Debuggerは有益です(そこらへんで、ニーズを持っているユーザー層とScript Debuggerの価格がマッチしていない)。

チェック項目5:変数名がさっぱりわからない

作者の意図が変数名からはさっぱり読み取れませんでした。小さなサブルーチン内でa、b、c、i、jといった変数名を使うこともありますが、極力、意図を反映したものにすべきでしょう。

チェック項目6:サブルーチンの仕様と呼び出す側の処理が合っていない

サブルーチン「DiveFolder」は、フォルダを渡すと再帰でその中身を探索しつつ、ファイルに対して所有者には読み書き可能な権限を、他のユーザーには読み出し可能な権限を与えるようになっています。

最初のプログラムでは、わざわざファイルを個別に渡すようになっており、サブルーチンを書いた人の意図を無視しています(サブルーチン側にもコメントがないことが問題。コメントを書かないのは本当に罪悪)。

チェック項目7:サブルーチン名が意味不明

だいたい、「DiveFolder」って、その中二病感満載の名前はなんじゃそりゃ(汗) 再帰でフォルダ内容の権限を書き換えるよ、という意図がわかる名前にしてほしいところです。あと、暗黙のルールでAppleScriptのハンドラ名(サブルーチン名)はCamel Caseで書くのがふつうです(DiveFolder→diveFolder)。

何度かやりとりをして、Keynote上で仕様を確認してみたりして、ようやく書き換えたのがこれ(↓)です。

AppleScript名:サーバー上の指定フォルダ内の全アクセス権限をローカルで書き換えて書き戻す
–  サーバー上にある特定フォルダ内のすべてのファイルを、ローカルにコピー(デスクトップ)し、
–  アクセス権限を変更して、サーバー上の元フォルダを消去して、ローカルのフォルダをアップロードする

set remoteFol to choose folder with prompt “サーバー上の、権限書き換え対象のフォルダを選択”

tell application “Finder”
  –権限を書き換えたフォルダを、あとでサーバーに書き戻すために準備
  
set returnFol to parent of remoteFol –最初に指定したフォルダの親フォルダを求めておく
  
  
–サーバー上のファイルをローカルのデスクトップ上にコピー
  
with timeout of 3600 seconds –遅いネットワーク(無線LANなど)を考慮(デフォルトでは180秒でタイムアウトでエラーに)
    set aLocalFol to (duplicate remoteFol to desktop with replacing) –同名のフォルダがあったら上書き
  end timeout
  
  
–ローカルのファイルをすべて権限書き換え
  
chmodRecursive(aLocalFol) of me
  
  
–サーバー上のフォルダを削除
  
delete remoteFol –shell scriptで”rm -rf”したくなる、、
  
empty trash
  
  
–サーバーにアップロード
  
with timeout of 3600 seconds –遅いネットワーク(無線LANなど)を考慮(デフォルトでは180秒でタイムアウトでエラーに)
    duplicate aLocalFol to returnFol
  end timeout
  
  
–あとしまつ。デスクトップ上にコピーしてきたフォルダを抹消
  
delete aLocalFol
  
empty trash
  
end tell

–指定フォルダ以下のすべてのファイルの権限を書き換える
on chmodRecursive(thePath) –サブルーチン名がぜんぜん意味不明だったのでリネーム
  tell application “Finder”
    
    
–ファイルに対しての処理を行う
    
set theFiles to every file of thePath
    
repeat with aFile in theFiles
      set owner privileges of aFile to read write
      
set everyones privileges of aFile to read only
    end repeat
    
    
–フォルダに対しての処理を再帰呼び出しで行う
    
set theFolders to every folder of thePath
    
repeat with aFolder in theFolders
      chmodRecursive(aFolder) of me –ここで再帰
    end repeat
    
  end tell
end chmodRecursive

★Click Here to Open This Script 

2015/02/08 Photoshop Action Setをインストールする

Photoshop Action SetをインストールするAppleScriptです。

・・・どこにもPhotoshopのコントロール部分がありませんが、これでいいんです。

Photoshopの自動化を行うにあたって、Script側に提供されている機能が決して多くはないため、Photoshop ActionでGUI上の操作を記録して、Actionを併用しつつScriptで処理するというスタイルが一般的です。つまり、Actionの有無や内容が期待した通りになっていることがたいへんに重要です。

以前に、海外の仕事で調査を行っていたときに、Photoshopがサポートしているファイルタイプ(=Photoshopがオープンできるファイルタイプ)に、Photoshop Action Setが存在していることに気づきました。

Photoshop Action Setはファイルに書き出すことができるのですが、これを各環境にインストールするあたりの操作を自動で行うことができずに、なかなかスマートな解決策がないもんだなぁ、と思っていました。

actionset.png

ところが、単にPhotoshop Action SetのファイルをPhotoshopのアプリケーションアイコンにドラッグ&ドロップすればPhotoshopにインストールできることがわかりました(盲点)。

そこで、その操作をAppleScriptで再現してみたら・・・問題なくインストールできました。アプリケーションバンドル中にPhotoshop Action Setのファイルを仕込んでおいて、Photoshop上に該当のAction Setが存在していなかったら、インストール・・・ということをやってみました。SandBox化したアプリ内でも実行できたので、割といい感じです。

Photoshop Actionの存在確認は(JavaScriptをまじえつつ)行えるので、存在していない場合にはAction Setを自動でインストールさせることが可能です。

AppleScript側で関知しないところでユーザーがAction Setの内容を改ざんするなどして、処理内容が維持できなくなる事態を防ぐべく、Action SetをScriptからインストール/アンインストールすることは重要です。

AppleScript名:Photoshop Actionをインストールする
set anActionFile to choose file with prompt “Choose Photoshop Action File”

tell application “Finder”
  set appFile to application file id “com.adobe.photoshop”
  
open anActionFile with appFile
end tell

★Click Here to Open This Script 

2015/02/08 起動中のプロセスの存在確認

Bundle IDで指定したプロセスが起動しているかどうかを確認するAppleScriptです。

AppleScript的には、System Eventsを経由してプロセスの起動中確認を行います。

AppleScript名:指定Bundle IDのプロセス存在確認(AS)
use AppleScript version “2.4″
use scripting additions

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshop”)
–> true

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshopoo!”)
–> false

on chkAppProcesByBundleID(aBundleID as string)
  tell application “System Events”
    set a to every process whose bundle identifier is aBundleID
    
if length of a 1 then
      return true
    else
      return false
    end if
  end tell
end chkAppProcesByBundleID

★Click Here to Open This Script 

しかし、この方法ではもしもMac App Storeに申請するアプリケーションで、System Eventsへのアクセスが封じられたらおしまいです。一応、shell script経由でpsコマンドを実行するという手段もありますが・・・

そこで、ASOCでCocoaの機能を用いてプロセスの存在確認を行ってみました。もうちょっと短く書けそうな気配もするのですが、とりあえず。

AppleScript名:指定Bundle IDのプロセス存在確認(ASOC)
– Created 2015-02-08 by Takaaki Naganoya
– 2015 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit”

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshop”)
–> true

set aRes to chkAppProcesByBundleID(“com.adobe.Photoshopoo!”)
–> false

on chkAppProcesByBundleID(aBundleID as string)
  set appArray to current application’s NSWorkspace’s sharedWorkspace’s runningApplications()
  
set appList to appArray’s ASify() as list
  
  
repeat with i in appList
    set anID to (i’s bundleIdentifier()) as string
    
if anID = aBundleID then
      return true
    end if
  end repeat
  
  
return false
end chkAppProcesByBundleID

★Click Here to Open This Script 

2015/02/08 指定アプリケーションの存在確認

Bundle IDで指定したアプリケーションの存在確認を行うAppleScriptです。

古くから(Classic Mac OSの時代から)、AppleScriptにはFinder経由でアプリケーションの存在確認を行う手段が用意されてきました。いまはBunde IDで、Classic Mac OS時代にはcreator codeで存在確認を行ってきましたが、同様にFinderに対して問い合わせを行っていました。

AppleScript名:指定アプリケーションの存在確認(AS)
use AppleScript version “2.4″
use scripting additions

set aRes to chkAppIsInstalled(“com.adobe.photoshop”)
–> true

on chkAppIsInstalled(aBundleID as string)
  try
    tell application “Finder”
      set a to application file id “com.adobe.photoshop”
    end tell
    
return true
  on error
    return false
  end try
end chkAppIsInstalled

★Click Here to Open This Script 

そのため、一般的にはFinderで確認する方法で問題はないのですが、もしもMac AppStoreに申請を行うASOCのアプリケーションでFinder経由の確認を行っていた場合に、唐突に「この方法ではダメ」と言われかねません。

そこで、Cocoaの機能を利用して確認を行う方法について調査しておきました。速度面でとくに通常のASにくらべて有利ということはありませんが、SandBox内での実行が制限されづらいだろうということで書いておきました。

実際、有名なところではログイン時に自動起動されるStartup ItemsにAppleScript経由で登録する方法を採用すると、Mac App Store申請時にリジェクトされるという制限が知られています。

AppleScript名:指定アプリケーションの存在確認(ASOC)
– Created 2014-12-23 by Takaaki Naganoya
– 2014 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “AppKit”

set aRes to chkAppIsInstalled(“com.adobe.photoshop”)
–>  true

on chkAppIsInstalled(aBundleID as string)
  set aRes to current application’s NSWorkspace’s sharedWorkspace()’s URLForApplicationWithBundleIdentifier:aBundleID
  
set bRes to (aRes is not equal to missing value)
  
return bRes
end chkAppIsInstalled

★Click Here to Open This Script 

2014/11/17 Finder Windowを円運動 v3

FinderのWindowを新規作成してぐるぐる回すAppleScriptです。

あまり手間をかけずに、複数Windowの回転に対応させました。

当初は、内部でスレッドを発生させて1Windowあたり1スレッドで管理するなど、いろいろ実装方法を検討してみましたが・・・何も、こんな意味のないくだらないScriptにそこまで血眼になる必要はないので、一番楽ができそうな方法で実現してみました。

プロパティ「maxWin」にWindow枚数を設定しておくと、その数だけFinder Windowを作成し、回転させます。手元のMacBook Pro Retina Mid 2012(寝床でバッテリ駆動中)では8ぐらいが上限っぽい感じでしたが(きれいに見える上限)、さらに強力なマシンでは数を増やして実行してみるとよいでしょう。

wins.png

AppleScript名:Finder Windowを円運動 v3
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit” – for NSScreen

property aNum : 300
property aOffset : 0
property maxWin : 8
property winList : {}
property randList : {}
property winSize : 400

–Initialize
set winList to {}
set randList to {}

repeat maxWin times
  tell application “Finder”
    activate
    
set aWin to make new Finder window
    
    
tell aWin
      set toolbar visible to false
      
set sidebar width to 0
      
set statusbar visible to false
      
set position to {100, 100}
      
set bounds to {100, 100, 100 + winSize, 100 + winSize}
    end tell
    
    
set the end of winList to aWin
    
set the end of randList to {random number from 0 to 400, random number from 0 to 400, random number from 1 to 360}
    
  end tell
end repeat

–Main
repeat with i from 1 to 360 by 6
  
  
repeat with ii from 1 to maxWin
    
    
set aWinObj to contents of item ii of winList
    
set {aRandX, aRandY, aRandDegree} to item ii of randList
    
    
set aDeg to i + aRandDegree
    
    
set aSinNum to (current application’s SMSFord’s sinValueOf:aDeg) as real
    
set aCosNum to (current application’s SMSFord’s cosValueOf:aDeg) as real
    
    
set x to ((aNum * aSinNum) + aNum) * 2.0 + aOffset
    
set y to (aNum * aCosNum) + aNum + aOffset
    
    
ignoring application responses
      tell application “Finder”
        tell aWinObj
          set position to {(x as integer) + aRandX, (y as integer) + aRandY}
        end tell
      end tell
    end ignoring
    
  end repeat
  
end repeat

–Sweep
tell application “Finder”
  repeat with i in winList
    tell i
      close
    end tell
  end repeat
end tell

★Click Here to Open This Script 

2014/11/17 Finder Windowを円運動 v2

FinderのWindowを新規作成してぐるぐる回すAppleScriptです。

なぜか、海外から好評を博して、びみょーにアップデートしました。

変更点:
Finderをactivateするようにした(そんなに変わらない気も、、、)
Satimage OSAXの予約語とコンフリクトを起こすasin, acosの変数名を変更した

複数スレッドを生成して、複数のFinder Windowをズラしながらぐるぐる回せると「やったな!」という感じがしていいかもしれません。自己満足ですが・・・。

AppleScript名:Finder Windowを円運動 v2
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit” – for NSScreen

property aNum : 300
property aOffset : 0

set {newX, newY} to (current application’s NSScreen’s mainScreen()’s frame()’s |size|()) as list

tell application “Finder”
  activate
  
set aWin to make new Finder window
end tell

repeat with i from 1 to 360 by 6
  
  
set aSinNum to (current application’s SMSFord’s sinValueOf:i) as real
  
set aCosNum to (current application’s SMSFord’s cosValueOf:i) as real
  
  
set x to ((aNum * aSinNum) + aNum) * 2.0 + aOffset
  
set y to (aNum * aCosNum) + aNum + aOffset
  
  
tell application “Finder”
    tell aWin
      set position to {x as integer, y as integer}
    end tell
  end tell
  
end repeat

tell application “Finder”
  tell aWin
    close
  end tell
end tell

★Click Here to Open This Script 

2014/11/17 Finder Windowを円運動

FinderのWindowを新規作成してぐるぐる回すAppleScriptです。

実行にはASObjCExtras.frameworkが必要なので、事前にインストールが必要です。楕円軌道でぐるぐるFinder Windowを回します。それだけです。

この手の、意味がぜんぜんないAppleScriptというのが割とエンドユーザー受けがよかったりするので、載せておきます。

Classic Mac OSの時代に、システムフォルダ内の名前に「A」を含むフォルダを開閉させる「open a」という意味のないScriptを書いてデモしたら、何かものすごい処理をしているように見えて受けがよかった、ということがありました。

ASObjCExtras.frameworkの三角関数機能を利用しています。一応、メイン画面のサイズを取得して円運動の大きさとかオフセット値とか扁平率に反映しようかと思ったものの、とくによいアイデアが思い浮かばなかったので、求めてそれっきり放置状態です。

img_0246_resized.png

1994年ごろに購入した「The Tao Of AppleScript」(日本語訳版)にFinderのウィンドウを四角く移動させるScriptが掲載されており、自分はこれを見て「なんて意味のない処理なんだ!」と呆れて登場当時のAppleScriptへの興味を失ってしまいましたが、他のユーザーがこの円運動Scriptを見て呆れないか心配です(^ー^;;

AppleScript名:Finder Windowを円運動
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
use framework “ASObjCExtras”
use framework “AppKit” – for NSScreen

property aNum : 300
property aOffset : 0

set {newX, newY} to (current application’s NSScreen’s mainScreen()’s frame()’s |size|()) as list

tell application “Finder”
  set aWin to make new Finder window
end tell

repeat with i from 1 to 360 by 6
  
  
set aSin to (current application’s SMSFord’s sinValueOf:i) as real
  
set aCos to (current application’s SMSFord’s cosValueOf:i) as real
  
  
set x to ((aNum * aSin) + aNum) * 2.0 + aOffset
  
set y to (aNum * aCos) + aNum + aOffset
  
  
tell application “Finder”
    tell aWin
      set position to {x as integer, y as integer}
    end tell
  end tell
  
end repeat

tell application “Finder”
  tell aWin
    close
  end tell
end tell

★Click Here to Open This Script 

2014/09/12 選択中のスクリーンショットから必要なもの以外削除

Shift-Command-3で作られる画面のスクリーンショットの画像ファイルを選択しておき、複数ディスプレイ接続時にできる「本来は必要ではない別のディスプレイ上のスクリーンショット」を削除するために作ったAppleScriptです。

Mac OS XではShift-Command-3で画面表示内容のスクリーンショットを画像に保存できます(常識レベルのお話)。これが、1つのディスプレイだけだと、

スクリーンショット 2014-09-12 13.01.59

といったファイル名で、デスクトップに日時を反映させたファイル名で作成されるわけですが、

bad_disp_arrange.png

といったように、複数台のディスプレイを接続している場合には、

・プライマリディスプレイ
スクリーンショット 2014-09-12 13.01.59

・セカンダリディスプレイ
スクリーンショット 2014-09-12 13.01.59(2)

といったように、プライマリ「以外の」ディスプレイのスクリーンショットにはその番号が末尾に付属します。OS Xでは6台までのディスプレイを認識するため、この数字の最大数は6ということになります。

きょうび、たいていのアプリケーションの表示は1台のディスプレイ内で完結していますので(昔みたいに、複数台のディスプレイにまたがった表示はしないので)、特定のアプリケーションのスクリーンショットをとっておきたい場合には、余計なディスプレイのスクリーンショットは「ゴミとして捨てる」場合がほとんどです。

そこで、デスクトップ上のスクリーンショットのファイルを選択しておいて、

screnshot1.png

本AppleScriptを実行。

screenshot2.png

どのディスプレイ用のスクリーンショットを残すか聞いてきますので、選択すると指定したディスプレイ以外のスクリーンショットはゴミ箱に移動されます。

Finder上で選択したファイルが「画面のスクリーンショットかどうか」の判定まではしていないので、不安であればそうした処理も追加するとよいでしょう。

スクリプト名:選択中のスクリーンショットから必要なもの以外削除
–選択中のファイル一覧をalias listで取得
tell application “Finder”
  activate
  
set aList to selection as alias list
end tell

–接続中のディスプレイをかぞえる
tell application “System Events”
  set dCount to count every desktop
end tell

–選択肢の作成
set dnList to {}
repeat with i from 1 to dCount
  set the end of dnList to (“(” & i as string) & “)” –全角カッコを指定「(」、[)」
end repeat

–残す項目を選ぶ
set aRes to choose from list dnList with prompt “どの画面のスクリーンショットを残しますか?” default items {contents of first item of dnList} with title “不要な画像をゴミ箱へ” without empty selection allowed
if aRes = false then
  display dialog “処理を中止します。” buttons {“OK”} giving up after 10 with title “キャンセルされました” with icon 2
  
return
end if

–選択された項目が何アイテム目かをサーチ(そういう命令があったかも、、、)
set aaRes to contents of first item of aRes

set aResNum to 1
repeat with i in dnList
  set j to contents of i
  
if j = aaRes then
    exit repeat
  end if
  
set aResNum to aResNum + 1
end repeat

–log {”aResNum”, aResNum}

if aResNum = 1 then
  –プライマリディスプレイ上のスクリーンショットを残すことを選択
  
set delList to (rest of dnList)
  
  
repeat with i in aList
    
    
tell application “Finder”
      set j to name of i
    end tell
    
    
–ファイル名に削除対象文字を含んでいるかどうかチェック
    
repeat with ii in delList
      set jj to (contents of ii) as string
      
–log {jj, j}
      
      
if j contains jj then
        tell application “Finder”
          delete i
        end tell
      end if
      
    end repeat
    
  end repeat
  
else
  –セカンダリディスプレイ上のスクリーンショットを残すことを選択
  
repeat with i in aList
    tell application “Finder”
      set j to name of i
    end tell
    
    
if j does not contain aaRes then
      tell application “Finder”
        delete i
      end tell
    end if
  end repeat
end if

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

2014/09/03 ファイル名の冒頭部分でフォルダを作成してフォルダ分け

ファイル名が「xxxxx_yyyyyyyy.xxx」などとなっている場合に、ファイル名の冒頭部分の「xxxxx」でフォルダを新規作成し、ファイル名冒頭が同じファイルを作成したフォルダに移動させるAppleScriptです。

大量の画像を含むフリー画像素材集をダウンロードして、そのままだと整理しづらかったのでささっとScriptを書いて整理してみました。

finder_file_sep.png

……ささっと書いたのはよかったのですが、なぜか実行にやたらと時間がかかり…………OSのバグか? などと思ってみたものの、DiskUtility.appを実行してSSDの権限修復などをいったん行ってから実行したら、すぐに処理が終わるようになりました。

もしも、AppleScriptでファイル処理を行ってみて、異様なほど時間がかかる場合には(処理にもよりますが)、ディスクユーティリティーを実行してSSD/HDDのチェックを行ってみてください。

こういうScriptを書いて走らせていると、つくづくHDDの時代は終わったんだなーと感じます。

スクリプト名:ファイル名の冒頭部分でフォルダを作成してフォルダ分け
script spd
  
  
property aList : missing value –ファイルを入れる(alias list)
  
property cList : missing value –フォルダ名を入れる
  
end script

set aList of spd to {}
set cList of spd to {}

set aFol to choose folder with prompt “フォルダを選択してください”
set aFolStr to aFol as string

tell application “Finder”
  tell folder aFolStr
    set aList of spd to every file as alias list
  end tell
  
  
repeat with i in (aList of spd)
    
    
set j to contents of i
    
set aName to name of j
    
set fName to getFolNameBeforeSeparator(aName, “_”) of me
    
    
set tFol to aFolStr & fName & “:”
    
    
if fName is in (cList of spd) then
      –フォルダが存在する場合
      
ignoring application responses
        move j to folder tFol
      end ignoring
      
    else
      –フォルダが存在しない場合
      
set the end of (cList of spd) to fName
      
      
if not (exists of (folder tFol)) then
        set newFol to make new folder with properties {name:fName} at folder aFolStr
        
do shell script “sync”
      end if
      
      
ignoring application responses
        move j to folder tFol
      end ignoring
      
    end if
    
  end repeat
  
  
end tell

–与えられた文字列(たぶんファイル名)のうち、先頭から指定セパレータまでの間をフォルダ名として返す
on getFolNameBeforeSeparator(aName, aSeparator)
  set aLoc to offset of aSeparator in aName
  
if aLoc = 0 then
    return “”
  else
    set aStr to text 1 thru (aLoc - 1) of aName
    
return aStr
  end if
end getFolNameBeforeSeparator

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

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対応、非対応のアプリ数をカウントする

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/05/26 Finderのフィルタ参照にファイル名の0を無視するバグ

US AppleがホスティングしているAppleScript Users MLで話題になっていた件で、あとからMLの話題に気付いて自分でも確認してみました。

フォルダ中に、

  Test_1.png
  Test_01.png
  Test_001.png
  Test_0001.png
  Test_00001.png

などのファイルが存在している状態で、

スクリプト名:ファイルの存在確認 10.9
set aFol to choose folder
set aFolStr to aFol as string

tell application “Finder”
  tell folder aFolStr
    set aList to name of every file whose name is “Test_1.png”
  end tell
end tell
–> {”Test_00001.png”, “Test_0001.png”, “Test_001.png”, “Test_01.png”, “Test_1.png”}

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

といったAppleScriptを実行すると…………すべてのファイルが取得できてしまいます。

数字の後ろに「0」が付いた場合は同一視しないのですが(例:「Test_10.png」はきちんと区別する)、正確にいえばプレフィックスの「0」を無視するという症状のようです(逆に、高度かつ余計な処理を行ってしまっているような……)。

実戦レベルのAppleScriptでは、たいてい1つのフォルダだけの内容を取得することは少なくて……指定フォルダ以下のすべての階層のフォルダからファイルを取得して抽出、といった処理が多いので、逆に単純な処理すぎて見過ごしていました。

なお、本症状はMac OS X 10.6.8、10.7.5、10.8.5、10.9.3で確認されています(それ以下のOSバージョンはさすがに実行環境が……)。

迂回方法

いくつか考えられます。do shell script経由でファイル名を取得して文字列比較を行えば、とくに問題はありません。フォルダ中に入っているファイル数が数千とか数万のオーダーにのぼる場合には、do shell script経由で取得して判断しています。

ただ……そこまで大げさではない場合には、ちょっと書き換えれば大丈夫です。

スクリプト名:ファイルの存在確認 10.9_recover
set aFol to choose folder
set aFolStr to aFol as string

tell application “Finder”
  tell folder aFolStr
    set aList to name of every file whose name is “Test_1.png” and name ends with “Test_1.png”
  end tell
end tell
–> {”Test_1.png”}

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

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

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

2014/04/22 指定のディレクトリ構造のみ別の場所にコピー

テストデータの納品を行うのに、実データをまるごと送ると大変な容量になるので、まずは速報ベースでデータディレクトリ構造および検証結果ログデータをお送りする際に、元のテストデータからディレクトリ構造だけ別の場所に再現するときに使用したAppleScriptです。

納品時に全パラメータの組み合せでテスト演算を行い、そのテスト演算を複数のOS環境など異なる条件下で実施。照合についてはAppleScriptで全自動化することで、どんなに退屈でミスが許されない作業であっても安心して実施できるようになってきました。

testdir_copy.png

ただし、1万を超えるチェック画像データを生データのまま送るとデータ量が大きすぎてオンラインストレージでも心もとないので、軽いデータだけにして送ることに。テストディレクトリ構造だけ別の場所にコピーして、テキストログだけ手でコピー……という作業をやっていました。フォルダを手で作りはじめて、あまりの機械的な作業にイヤになり、この作業自体もAppleScriptに行わせることにしました。それがこのScriptです(前提が長いな〜)。

folcon.png

本AppleScript実行前に、コピー対象のフォルダをFinder上で選択しておく必要があります。複数フォルダを選択していた場合については考慮していないため、エラーになります。

なお、テストデータフォルダについては、すべてテスト内容を表した「英数字のみ」で表現していたので、日本語を含むフォルダでは実験していません。

スクリプト名:指定のディレクトリ構造のみコピー
script spd
  property aList : missing value
  
property bList : missing value
  
property cList : missing value
end script

set (aList of spd) to {}
set (bList of spd) to {}
set (cList of spd) to {}

tell application “Finder”
  set aFol to selection
  
if aFol = {} then return
end tell

set tFol to choose folder with prompt “ディレクトリ構造のコピー先を選択”
set tFolStr to tFol as string

tell application “Finder”
  set aFol to aFol as alias
  
set aFolStr to aFol as string
  
  
–指定フォルダ以下のファイル/フォルダをすべて取得
  
with timeout of 3600 seconds
    set (aList of spd) to (entire contents of folder aFol) as alias list
  end timeout
  
  
–Folderだけ収集
  
repeat with i in (aList of spd)
    set aPath to (contents of i) as string
    
if aPath ends with “:” then
      set the end of (bList of spd) to (contents of i)
    end if
  end repeat
  
  
–Folderを別の場所に掘る
  
repeat with i in (bList of spd)
    set bPath to (contents of i) as string
    
set cPath to repChar(bPath, aFolStr, tFolStr) of me
    
    
set cPathPosix to quoted form of POSIX path of cPath
    
    
–display dialog cPathPosix
    
    
–ディレクトリだけ作成
    
try
      do shell script “mkdir -p “ & cPathPosix –日本語のフォルダ名については未検証
    end try
    
  end repeat
  
end tell

–文字置換ルーチン
on repChar(origText, targStr, repStr)
  set {txdl, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, targStr}
  
set temp to text items of origText
  
set AppleScript’s text item delimiters to repStr
  
set res to temp as text
  
set AppleScript’s text item delimiters to txdl
  
return res
end repChar

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

2013/08/26 指定ファイルのクリエーターとファイルタイプを変更する

指定ファイルのクリエーターとファイルタイプを変更するAppleScriptです。

OS X 10.6以降では、Finder上でクリエーターとファイルタイプを無視する……ことになっています。しかし、ちょっと古めのプログラム(QuickTime Player 7とか)だと、これらをファイルに書き込んで……あろうことか、Finderがこれらを無視するはずが、考慮して「情報を見る」の内容を変更していたりします。

おかげで、MPEG-4できちんとファイル書き出しをしたはずなのに、Finder上の情報で「QuickTimeムービー」などと表示され、海外のお客から「もしかしてこれだと困るかも〜」と指摘される始末。

そこで、ファイルタイプとクリエーターを変更するというよりは「消去する」ことを目的として本ルーチンを作成しました。

スクリプト名:指定ファイルのクリエーターとファイルタイプを変更する
set a to choose file
set aRes to changeFileCreatorAndFileType(a, missing value, missing value) of me

–指定ファイルのクリエーターとファイルタイプを変更する
on changeFileCreatorAndFileType(aFile, aCreator, aFileType)
  
  
try
    tell application “Finder”
      set file type of file aFile to aFileType
      
set creator type of file aFile to aCreator
    end tell
  on error error_message
    return error_message
  end try
  
  
return true
  
end changeFileCreatorAndFileType

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

2013/06/22 Finder上で選択中のフォルダをDMGに変換してZip圧縮

Finder上でフォルダを選択して、本AppleScriptをScript Menuから呼び出して実行すると、選択していたフォルダをDMG(Disk Image File)に変換して、さらにZip圧縮します。オリジナルのフォルダと途中のDMGファイルは自動で削除されます。

Finder上で選択されていたものの中にファイルが含まれていた場合には、ファイルについてはスキップします。

HDDやSSDの容量が足りない場合に、フォルダ単位でDMG化→ZIP圧縮して容量を稼ごうとするときに使うものです。しばらくつかいそうもない資料とか、やたらとファイル数があるWeb系の(古めの)コンテンツなんかをアーカイブするときに使用します。

テストを繰り返して、使ってみても大丈夫な感じではあるのですが、より広域に使用テストを行っていただいたほうがよいだろうと考えて、掲載してみました。問題があれば、お知らせください。

スクリプト名:Finder上で選択中のフォルダをDMGに変換してZip圧縮

property deleteV : true –DMG変換後に対象フォルダの削除フラグ(trueで削除)
property zipDmg : true –DMG作成後にZip圧縮するフラグ(trueで圧縮+DMG削除、falseだと何もしない)

–Finder上の選択項目を取得、選択されていない場合には処理終了
tell application “Finder”
  set selList to selection
  
if selList = {} or selList = “” or selList = missing value then
    activate
    
display dialog “何も選択されていません。” buttons {“OK”} default button 1 with icon 1
    
return
  end if
end tell

–選択されたアイテムのうちフォルダだけを抽出
if class of selList is not equal to list then
  set aList to (selList as alias) as list –Mac OS X 10.4対策
else
  set aList to {}
  
repeat with i in selList
    –選択したアイテムのうちフォルダであるものだけを処理対象とする
    
set j to (contents of i) as alias
    
set aInfo to info for j
    
if folder of aInfo = true then
      set the end of aList to j
    end if
  end repeat
end if

tell application “Finder”
  
  
set dmgList to {}
  
  
–選択中のアイテムを順次処理するループ
  
repeat with i in aList
    set the end of dmgList to makeDMGfromFolderAlias(i, “”) of me –パスワードは付けない
    
    
–処理後のフォルダを削除する処理
    
if (deleteV as boolean) = true then
      deleteFolderItself(i) of me
    else
      –元フォルダを削除しない場合、元フォルダの名前を変更する
      
tell application “Finder”
        set aName to name of i
      end tell
      
      
set aName to aName & “_origFol”
      
      
tell application “Finder”
        set name of i to aName
      end tell
    end if
  end repeat
  
  
  
–DMG作成後にZip圧縮する(trueで圧縮+DMG削除)
  
if zipDmg = true then
    repeat with i in dmgList
      set j to contents of i
      
      
set f1Path to quoted form of j –DMGファイルのPOSIX Path
      
set f2Path to quoted form of (j & “.zip”) –ZipファイルのPOSIX Path
      
      
–タイムアウト時間は2時間
      
with timeout of 7200 seconds
        do shell script “/usr/bin/zip -r -j “ & f2Path & ” “ & f1Path
        
do shell script “/bin/rm -f “ & f1Path
      end timeout
      
    end repeat
  end if
end tell

–指定のフォルダ(alias)をDiskImageに変換する
on makeDMGfromFolderAlias(aaSel, aPassword)
  
  
set aPassword to aPassword as string
  
  
tell application “Finder”
    set fn to name of aaSel
  end tell
  
  
set aDir to (POSIX path of aaSel)
  
set aDir to quoted form of aDir
  
  
set fp2 to do shell script “dirname “ & aDir
  
set fp2 to fp2 & “/”
  
  
set outPath to (fp2 & fn & “.dmg”)
  
  
if aPassword is not equal to “” then
    –パスワードつきの場合
    
set aCMD to “printf ‘” & aPassword & “‘ | hdiutil create -encryption -srcfolder “ & aDir & ” “ & (quoted form of outPath)
  else
    –パスワードなしの場合
    
set aCMD to “hdiutil create -srcfolder “ & aDir & ” “ & (quoted form of outPath)
  end if
  
  
set fp3 to do shell script aCMD
  
  
return outPath
  
end makeDMGfromFolderAlias

–指定フォルダ内をすべて削除し、そのフォルダ自体も削除
on deleteFolderItself(aFol)
  set aU to (quoted form of POSIX path of aFol)
  
try
    do shell script “rm -rf “ & aU
  end try
end deleteFolderItself

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

2013/06/20 指定フォルダが所属するDiskの空き容量が制限値よりも多いかチェック

指定フォルダが所属するDiskの空き容量が、制限値よりも多いかどうかチェックするAppleScriptです。

finder1.png

Finder上の空き容量表示が上記のような場合に、このDisk内のフォルダを指定すると、指定の制限値と実際の空き容量を比較し、制限値よりも空きが多い場合にはtrueを、そうでない場合にはfalseを返します。

制限値については、「32G」「105M」といった単位つきの表現が使えます。Diskの空き容量の計算方法はMac OS X 10.6で変更(1K=1000)されたため、基数を1000に指定しておく必要があります。Mac OS X 10.6より古いOSで動かす場合には、基数を1024に指定してください。

スクリプト名:指定フォルダが所属するDiskの空き容量が制限値よりも多いかチェック
set aFol to choose folder
set dRes to chkFreeSpaceOfFoldersDisk(aFol, “134G”) of me
–> true

–指定フォルダが所属するDiskの空き容量が指定の制限値よりも多いかチェック
on chkFreeSpaceOfFoldersDisk(aFol, minimumDiskSpace)
  set minimumSpace to procMetricPrefix(minimumDiskSpace, 1000) of me –Mac OS X 10.6以降だと1000,それ以前だと1024を指定
  
  
set fRes to getFreeSpace(aFol) of me
  
  
considering numeric strings
    if fRes minimumSpace then
      return false –空き容量が制限値よりも少なかった
    else
      return true –多かった
    end if
  end considering
  
end chkFreeSpaceOfFoldersDisk

on getFreeSpace(aFol)
  set aFolStr to aFol as string
  
set aList to parseByDelim(aFolStr, “:”) of me
  
set aDiskName to contents of first item of aList
  
  
tell application “Finder”
    set aDisk to disk aDiskName
    
set aFree to free space of aDisk
  end tell
  
  
set numberString to Stringify(aFree) of me
  
  
return numberString
  
end getFreeSpace

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–数字の文字だけが入っているかどうかをテストする
–数字の文字のみから構成されていたらtrue、1文字でもそれ以外のものが入っていたらfalse
on detectContainsOnlyNumChar(testText)
  –Numeric文字列(大文字小文字は問わない)
  
set ankChar to {“0″, “1″, “2″, “3″, “4″, “5″, “6″, “7″, “8″, “9″, “.”, “-”}
  
  
set _testChar to testText as Unicode text
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is not in ankChar then
        return false
      end if
    end repeat
  end ignoring
  
  
return true
end detectContainsOnlyNumChar

–指数表示数値を文字列化
on Stringify(x) – for E+ numbers
  set x to x as string
  
set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {“E+”}}
  
if (count (text items of x)) = 1 then
    set AppleScript’s text item delimiters to {tids}
    
return x
  else
    set {n, z} to {text item 1 of x, (text item 2 of x) as integer}
    
set AppleScript’s text item delimiters to {tids}
    
set i to character 1 of n
    
set decSepChar to character 2 of n – “.” or “,”
    
set d to text 3 thru -1 of n
    
set l to count d
    
if l > z then
      return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d))
    else
      repeat (z - l) times
        set d to d & “0″
      end repeat
      
return (i & d)
    end if
  end if
end Stringify

–SI接頭辞つきの数値を具体的な数値の文字列に評価して返す
–https://en.wikipedia.org/wiki/Metric_prefix
on procMetricPrefix(numStrWithMetric, aBase)
  
  
if (aBase = 1024) or (aBase = 1000) then
    
    
set numPart to (text 1 thru -2 of numStrWithMetric) as integer
    
set aBaseStr to aBase as string
    
    
if numStrWithMetric ends with “K” then
      set multNum to 1
    else if numStrWithMetric ends with “M” then
      set multNum to 2
    else if numStrWithMetric ends with “G” then
      set multNum to 3
    else if numStrWithMetric ends with “T” then
      set multNum to 4
    else if numStrWithMetric ends with “P” then
      set multNum to 5
    else if numStrWithMetric ends with “E” then
      set multNum to 6
    else if numStrWithMetric ends with “Z” then
      set multNum to 7
    else if numStrWithMetric ends with “Y” then
      set multNum to 8
      
    else
      return false
    end if
    
    
set aCMD to “echo \” scale=10; “ & aBaseStr & “^” & (multNum as string) & “*” & numPart & “\” | bc”
    
set aRes to do shell script aCMD
    
return aRes
    
  else
    return false
    
  end if
end procMetricPrefix

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

2013/06/19 指定フォルダが所属するDiskの空き容量を取得する

指定フォルダが所属するDiskの空き容量を取得するAppleScriptです。

USBメモリ上のフォルダを指定したら、そのUSBメモリの空き容量を求めます。

サーバー上のQuotaがかかった(ユーザーごとの書き込み上限容量が設定された)状態の使用可能残容量を求めるといった用途は考慮していません。

スクリプト名:指定フォルダが所属するDiskの空き容量を取得する
set aFol to choose folder

set fRes to getFreeSpace(aFol) of me

on getFreeSpace(aFol)
  set aFolStr to aFol as string
  
set aList to parseByDelim(aFolStr, “:”) of me
  
set aDiskName to contents of first item of aList
  
  
tell application “Finder”
    set aDisk to disk aDiskName
    
set aFree to free space of aDisk
  end tell
  
  
set numberString to Stringify(aFree) of me
  
  
return numberString
  
end getFreeSpace

–与えられた文字列を、指定デリミタ文字でparseしてリストにして返す
on parseByDelim(aData, aDelim)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to aDelim
  
set dList to text items of aData
  
set AppleScript’s text item delimiters to curDelim
  
return dList
end parseByDelim

–数字の文字だけが入っているかどうかをテストする
–数字の文字のみから構成されていたらtrue、1文字でもそれ以外のものが入っていたらfalse
on detectContainsOnlyNumChar(testText)
  –Numeric文字列(大文字小文字は問わない)
  
set ankChar to {“0″, “1″, “2″, “3″, “4″, “5″, “6″, “7″, “8″, “9″, “.”, “-”}
  
  
set _testChar to testText as Unicode text
  
  
ignoring case
    repeat with i in _testChar
      set j to contents of i
      
if j is not in ankChar then
        return false
      end if
    end repeat
  end ignoring
  
  
return true
end detectContainsOnlyNumChar

–指数表示数値を文字列化
on Stringify(x) – for E+ numbers
  set x to x as string
  
set {tids, AppleScript’s text item delimiters} to {AppleScript’s text item delimiters, {“E+”}}
  
if (count (text items of x)) = 1 then
    set AppleScript’s text item delimiters to {tids}
    
return x
  else
    set {n, z} to {text item 1 of x, (text item 2 of x) as integer}
    
set AppleScript’s text item delimiters to {tids}
    
set i to character 1 of n
    
set decSepChar to character 2 of n – “.” or “,”
    
set d to text 3 thru -1 of n
    
set l to count d
    
if l > z then
      return (i & (text 1 thru z of d) & decSepChar & (text (z + 1) thru -1 of d))
    else
      repeat (z - l) times
        set d to d & “0″
      end repeat
      
return (i & d)
    end if
  end if
end Stringify

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

2013/06/01 指定フォルダ以下のファイル名をすべて取得してソートしてテキスト化して返す

指定フォルダ以下のファイルをすべて取得して、ターゲットの拡張子を持つもののファイル名だけを抽出し、昇順ソートしてテキストにして返すAppleScriptです。

この手のAppleScriptは作り捨てしているので、何回か同じようなものを掲載しているかもしれません。それだけ、よく使う種類のものです。

指定フォルダ以下の特定の拡張子のファイルを求めるには、

(1)mdfindコマンド(spotlight)を使う
(2)Finderに対してentire contentsを求めてあとで条件に基づいて抽出する
(3)shell command(lsを再帰オプション付きで)実行

などの方法があり、用途に応じて使い分けています。

実行するマシンのDiskが高速なSSDだったので(MacBook Pro Retina)、今回はテストをかねて(2)を使いました。

こういう用途だと、一般的な選択は(1)です。ただし、検索対象となるDiskがネットワーク上の特殊な(Mac OS Xで稼働しているコンピュータではない)ものだったりすると、Spotlightによる検索が利かない可能性もあるため、そういうケースでは(1)は使えません。

このため、あまりシビアな用途ではない場面において、(1)以外の「手口」についても感触を試しておく必要があります。今回はそういうケースでした。

Finderの「entire contents」は、きわめて強力な機能なのですが……返ってくるデータ量がきわめて多いのと、そのままでは返ってきたデータをFinderのオブジェクト形式に変換するのに時間がかかるため、かなり昔(Classic Mac OS時代)から存在していたにも関わらず、実用性はいまひとつでした。実用性が出てきたのは、PowerPC G5が登場してきたあたりで……かつ、「as alias list」によって返り値をaliasのlistにcastできるようになったMac OS X 10.5以降と言って差し支えないと思います。

一応、Mac OS X 10.5以前にもentire contnetsの返り値をすべて文字列化することで高速に取得し、あとで文字列をparseするという高等テクニックが存在していたのですが、「as alias list」が使えるようになると、わざわざそんなことをしなくても済むようになりました。

抽出対象のファイル数が数万ファイルや数十万ファイルになる場合には(3)を使ったほうが安全に処理できるでしょう(ただ、shell経由で処理した後でalias形式に変換するなどの処理は発生します)。

スクリプト名:指定フォルダ以下のファイル名をすべて取得してソートしてテキスト化して返す
script spd
  property aList : {}
  
property bList : {}
  
property tOut : “”
end script

property targetFileExt : “.pdf” –取得するファイル名の拡張子

set aList of spd to {}
set bList of spd to {}
set tOut of spd to “”

set a to choose folder

tell application “Finder”
  
  
–entire contentsで指定フォルダ以下のファイル/フォルダをすべて取得
  
set aList of spd to entire contents of a as alias list
  
  
repeat with i in aList of spd
    set j to contents of i
    
set aName to name of j
    
    
–ファイル抽出
    
if aName ends with targetFileExt then
      set the end of bList of spd to aName
    end if
    
  end repeat
  
end tell

set aRes to shellSortAscending(bList of spd) of me –Sort Filename by name

set tOut of spd to “”
repeat with i in aRes
  set tOut of spd to tOut of spd & (i as string) & return
end repeat

return contents of tOut of spd

–入れ子ではないリストの昇順ソート
on shellSortAscending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (oBj’s list’s item (j - gap + 1) > temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortAscending

–入れ子ではないリストの降順ソート
on shellSortDescending(aSortList)
  script oBj
    property list : aSortList
  end script
  
set len to count oBj’s list’s items
  
set gap to 1
  
repeat while (gap len)
    set gap to ((gap * 3) + 1)
  end repeat
  
repeat while (gap > 0)
    set gap to (gap div 3)
    
if (gap < len) then
      repeat with i from gap to (len - 1)
        set temp to oBj’s list’s item (i + 1)
        
set j to i
        
repeat while ((j gap) and (oBj’s list’s item (j - gap + 1) < temp))
          set oBj’s list’s item (j + 1) to oBj’s list’s item (j - gap + 1)
          
set j to j - gap
        end repeat
        
set oBj’s list’s item (j + 1) to temp
      end repeat
    end if
  end repeat
  
return oBj’s list
end shellSortDescending

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

2013/05/24 Finder上で選択中のファイルをPreviewでオープンして保存してクローズ

Finder上で選択中のファイル(たぶんPDF)をPreview.appでオープンして、保存してクローズ……を繰り返すAppleScriptです。

PhotoshopでPDFを加工したところ、そのままではファイルサイズが大きく、古いOS(Mac OS X 10.4.11とか)では内容を確認できない状態でした。

……ちょっと困りました。そこで、OS X 10.8上のPreview.appでファイルを保存し直したところ、ファイルサイズも小さくなり、古いOSでもオープンできるようになりました。

何か、ほかにも回避方法はありそうですが……とりあえず、本AppleScriptによって、Finder上でPhotoshopによる加工を行ったPDFを選択しておき、Scriptを実行することですべて保存し直します。

なお、本AppleScriptはGUI Scriptingを利用しているため、あらかじめシステム環境設定の「アクセシビリティ」で「補助装置にアクセスできるようにする」にチェックを入れておく必要があります。また、将来のOSバージョンアップによってPreview.appのメニュー内容が変更になった場合には、そのままでは動かず修正(メニューアイテム番号部分のみ)が必要になる可能性が高いです。

スクリプト名:Finder上で選択中のファイルをPreviewでオープンして保存してクローズ
tell application “Finder”
  set aList to selection as alias list
end tell

repeat with i in aList
  
  
set j to contents of i
  
set jj to j as string
  
  
–Preview.appで選択されたファイルをオープンする
  
set appBundleID to “com.apple.Preview”
  
tell application “Finder”
    open file jj using application file id appBundleID
  end tell
  
  
delay 0.1
  
  
–Preview.appでファイル保存→クローズを行う
  
activate application “Preview”
  
tell application “System Events”
    tell process “プレビュー”
      click menu item 8 of menu 1 of menu bar item 3 of menu bar 1 –保存
    end tell
  end tell
  
  
delay 0.1
  
  
tell application “System Events”
    tell process “プレビュー”
      click menu item 5 of menu 1 of menu bar item 3 of menu bar 1 –閉じる
    end tell
  end tell
  
end repeat

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

2013/05/17 選択した書類ファイルをDockのアプリアイコンにドラッグ&ドロップ

選択した書類ファイルを、任意の(Bundle IDで指定した)アプリのDock上のアイコンにドラッグ&ドロップ……するのと同じ状態を作るAppleScriptです。

まず最初にお断りしておきますが、(AppleScriptObjCではない)通常のAppleScriptにドラッグ&ドロップの状態を作り出す機能はありません。

ありませんが、「任意のアプリで指定ファイルをオープンさせる」という機能がFinderにあります。GUIのフィードバックやDockへのドラッグ&ドロップ通知がないだけで、実行される内容はほぼ同じです。

まずは、どのアプリでオープンさせるかを調べるために、Finder上でアプリケーションのアイコンファイルを選択しておき、こんな(使い捨てレベルの)AppleScriptを実行。

スクリプト名:Finder上でアプリケーションを選択しておいて実行すると詳細情報をログ表示
tell application “Finder”
  set {a} to selection
  
properties of a
end tell

–> {class:application file, name:”Art Text 2.app”, index:38, displayed name:”Art Text 2″, name extension:”app”, extension hidden:true, container:folder “Applications” of startup disk of application “Finder”, disk:startup disk of application “Finder”, position:{92, 775}, desktop position:missing value, bounds:{60, 743, 124, 807}, kind:”アプリケーション”, label index:0, locked:false, description:missing value, comment:”", size:122256097, physical size:128839680, creation date:date “2013年4月12日金曜日 12:22:40″, modification date:date “2013年4月14日日曜日 12:47:54″, icon:missing value, URL:”file://localhost/Applications/Art%20Text%202.app”, owner:”システム”, group:”root”, owner privileges:read write, group privileges:read write, everyones privileges:read only, file type:”APPL”, creator type:”ARTT”, stationery:false, product version:”", version:”Art Text, version 2.4.1, Copyright © 2006-2012 BeLight Software, Ltd”, id:”com.belightsoft.ArtText2″, accepts high level events:true, has scripting terminology:false}

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

すると、選択したアプリケーションの詳細情報が表示されますので……「id」情報を調べます。ここでは、AppleScriptに非対応の「Art Text 2」の情報を表示しています。

Art Text 2のBundle IDが、「com.belightsoft.ArtText2」だと分ったので、これを次のAppleScriptに反映させ、選択したファイル(ファイル情報だけ渡せば別にダイアログ表示する必要はない)をオープンさせるようにします。

スクリプト名:指定ファイルを指定アプリでオープン(アプリアイコンへの書類ファイルのドラッグ&ドロップと等価)
set a to choose file

set appBundleID to “com.belightsoft.ArtText2″ –オープンさせたいアプリケーションのBundle ID

tell application “Finder”
  open file a using application file id appBundleID
end tell

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

だいたいは、AppleScript非対応のアプリケーションで、書類をドラッグ&ドロップすると自動でファイル変換を行ってくれるようなものをAppleScriptからコントロールするために利用することが多いです(ファイルの変換を行うものとか、エンコーダーとか)。

もちろん、指定したアプリが対応していない種類のファイルを開かせようとしても、開けません。どのような種類のファイルに対応しているかは、あらかじめ調べておく必要があります。

ここで指している「アプリケーション」とは、CocoaベースのMac OS Xの標準的なアプリケーションのことを指しています。Javaで作られたものや、クロスプラットフォーム開発ツールで作られた特殊なアプリケーションなどは対象外です。