Archive for the 'Finder' Category

03/12 Find same file name with different extension in same directory

This is a simple AppleScript to find same file name with different extension in same directory.

Sample Data:
finder1.jpg

Output Data:
–> {{”D120_a.jpg”, “D120_a.png”}, {”D120_c.gif”, “D120_c.jpg”, “D120_c.png”, “D120_c.txt”}}

スクリプト名:find same file name with different extension in same directory
–Speed up technic
script aRef
  property aList : {} –every file name of user selected folder ( work)
  
property bList : {} – every file name list (without duplicates) (work)
  
property cList : {} –duplicated file name list (work)
  
property dList : {} –output duplicated file names with different extensions
end script

–Initialize variables
set aList of aRef to {}
set bList of aRef to {}
set cList of aRef to {}
set dList of aRef to {}

set a to choose folder with prompt "Choose check Folder"

tell application "Finder"
  tell folder a
    set aList of aRef to name of every file
  end tell
end tell

–make pure file name list(without extension) to cList
repeat with i in aList of aRef
  set j to contents of i
  
set jj to retFileNameWithoutExt(j) of me
  
  
if jj is in bList of aRef then
    –duplicated file name & does not exist in cList
    
if jj is not in cList of aRef then
      set the end of cList of aRef to jj
    end if
    
    
set tmpName to jj & "."
    
    
tell application "Finder"
      tell folder a
        –set dList of aRef to dList of aRef & (name of every file whose name starts with tmpName)
        
set the end of dList of aRef to (name of every file whose name starts with tmpName)
      end tell
    end tell
    
  end if
  
  
set the end of bList of aRef to jj
end repeat

–Remove duplicates from List
set aRes to removeDuplicates(dList of aRef) of me

–> {{"D120_a.jpg", "D120_a.png"}, {"D120_c.gif", "D120_c.jpg", "D120_c.png", "D120_c.txt"}}

–Remove Duplicated Item from List
on removeDuplicates(aList)
  set newList to {}
  
repeat with i from 1 to (length of aList)
    set anItem to item 1 of aList
    
set aList to rest of aList
    
if {anItem} is not in aList then set end of newList to anItem
  end repeat
  
return newList
end removeDuplicates

–delete extension from file name
on retFileNameWithoutExt(fileNameStr)
  set fLen to length of fileNameStr
  
set revText to (reverse of (characters of fileNameStr)) as string –make reversed string
  
set anOffset to offset of "." in revText
  
set fRes to text 1 thru (fLen - anOffset) of fileNameStr
  
return fRes
end retFileNameWithoutExt

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

02/07 iTunesのMobileアプリをコピーしてすべて展開する

このAppleScriptは、iTunesに入っているiPhone/iPadのアプリを指定フォルダにコピーして、アーカイブを展開して、さらにアプリケーションバンドルを「ただのフォルダ」に変えるものです。

iTunesをコントロールして、iOSアプリの情報を取得しようとしても……iTunes上でアプリの情報を取得するための機能は(iTunesのAppleScript用語辞書には)一切用意されていません(selectionすら取得できないのには意図的なものを感じる)。でも、アプリの情報にアクセスするのに、iTunesの力は必要ありません。ファイル・アクセスだけで十分です。

iosap1.jpg

iOSのアプリは拡張子「.ipa」のファイルであり、このファイルはZipアーカイブの拡張子を変えただけのものなので、簡単に展開できます。

iosap2.jpg

展開すると「Payload」フォルダ内にiOSアプリケーションが展開されます。さらに、このiOSアプリの拡張子「.app」を外します。

iosap3.jpg

iOSアプリのアプリケーションバンドル中に入っている各種データをSpotlightでキーワード検索して探し出すことが可能になります。

iosap4.jpg

一度走らせれば一括処理できるので、2度目を実行する必要性はかなり低いのですが……。処理が簡単で、GUIアプリをコントロールしていないですし、処理を行ったMacBook Proでは4コアのCPUのほとんどが空いており……並列処理にはもってこいの内容です(が、使い捨ての処理なのでそこまでは……)。

とりあえず、EULAの文章などのサンプルを取り出すために、他の用件を片付けている間にAppleScriptを走らせて処理できました。予想外だったのは、すべてのアプリのアーカイブを展開したら容量が増えてHDDの空き容量が減って危ない目に……。

スクリプト名:iTunesのMobileアプリをコピーしてすべて展開する
–iTunesのデータフォルダを求める
set mFol to path to music folder
set mFolStr to mFol as string
set mFolStr to mFolStr & “iTunes:Mobile Applications:”

–home:Music:iTunes:Mobile Applicationsフォルダ内のipaファイルの一覧を取得する
try
  tell application “Finder”
    tell folder mFolStr
      set appList to (every file whose name ends with “.ipa”) as alias list
    end tell
  end tell
on error
  display dialog “Mobile Applicationsフォルダが存在しないか、Mobileアプリが存在しません。” buttons {“OK”} default button 1 with icon 1
  
return
end try

–ipaファイルを処理するループ
set appProcTmp to choose folder with prompt “iOSアプリケーションを展開する作業フォルダを指定”

set aCount to 1 –フォルダ名のカウンタ

repeat with i in appList
  –ipaからzipにリネーム
  
set j to contents of i
  
  
tell application “Finder”
    
    
–新規フォルダ作成
    
set newFolder to (make new folder at appProcTmp with properties {name:aCount as string})
    
set newFolder to newFolder as alias
    
    
–ipaファイルをコピー
    
set anAppFile to (duplicate j to newFolder)
    
set anAppFile to anAppFile as alias
    
    
–ipaファイルをzipにリネーム
    
set aName to name of anAppFile
    
set bName to retNameFromFilenameStr(aName) of me
    
set bName to bName & “.zip”
    
    
set name of anAppFile to bName –rename
    
  end tell
  
  
–unzipを実行してzipアーカイブを展開
  
set tmpFolPath to POSIX path of newFolder
  
set tmpPathPOSIXfull to POSIX path of anAppFile
  
try
    do shell script “cd “ & quoted form of tmpFolPath & ” && unzip “ & quoted form of tmpPathPOSIXfull
  on error erMes
    return {false, erMes}
  end try
  
–展開ここまで
  
  
  
–展開後のアプリケーションバンドルをただのフォルダに変える
  
tell application “Finder”
    tell folder (newFolder as string)
      tell folder “Payload”
        set appFileList to (every file whose name ends with “.app”)
        
set appFile to (contents of first item of appFileList) as alias
        
        
set tmpName to name of appFile
        
set newAppName to retNameFromFilenameStr(tmpName) of me
        
set name of appFile to newAppName
      end tell
    end tell
  end tell
  
  
  
set aCount to aCount + 1
  
end repeat

–ファイル名文字列から拡張子を外して返す
on retNameFromFilenameStr(fileNameStr)
  set fLen to length of fileNameStr
  
set revText to (reverse of (characters of fileNameStr)) as string –逆順テキストを作成
  
set anOffset to offset of “.” in revText
  
set fRes to text 1 thru (fLen - anOffset) of fileNameStr
  
return fRes
end retNameFromFilenameStr

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

01/09 指定Finder Windowのツールバー&サイドバーの表示、非表示をコントロール

指定Finder Windowのツールバーおよびサイドバーの表示/非表示状態を制御するAppleScriptです。

FinderのAppleScript用語辞書をオープンすると、サイドバーを表す要素が見つかりません。そこで、サイドバーの表示/非表示の制御はできないもの……と、思ってしまわれがちですが、サイドバーはウィンドウ上部のツールバーと表示/非表示制御が一括して行われているため、ツールバーの制御を行うと、一緒に表示状態をコントロールできます。

finwin1.jpg

finwin2.jpg

裏を返せば、サイドバー/ツールバーともに単独で状態を制御できないということになりますが、それはOSの(ウィンドウシステムの)仕様なので、言っても仕方のないところ。

AppleScriptで各種アプリケーションをコントロールするには、こうしたOSやアプリケーションの挙動に対する「暗黙のお約束」的な仕様を意識する必要があり、その典型的な例として挙げてみました(このサブルーチン自体には…………あまり利用価値がないような、、、サブルーチン化しなくても、もっと簡潔に書けるわけで)。

表示中のFinderのすべてのWindowに対して制御を行う場合には、tell every window……と書いたほうが効率的で、すべてのFinder Windowをリストに入れてループ処理……というのはAppleScript「らしい」やりかたではありません。ねんのため。

スクリプト名:指定Finder Windowのツールバー&サイドバーの表示、非表示をコントロール
tell application “Finder”
  set targWin to window 1 –最前面のWindowを指定。任意のWindow指定も可能
end tell

showHideToolbarAndSidebar(targWin, false) of me –非表示にする
–showHideToolbarAndSidebar(targWin, true) of me –表示にする

–指定Finder Windowのツールバー&サイドバーの表示、非表示をコントロール
on showHideToolbarAndSidebar(targetWindow, showF)
  try
    tell application “Finder”
      tell targetWindow
        set toolbar visible to showF
      end tell
    end tell
  end try
end showHideToolbarAndSidebar

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

01/03 作成日時からラジオ録音番組名を設定

録音したRadikoの音声ファイルを、それぞれの番組の条件リストをもとにリネームするAppleScriptです。

r0013976.JPG

自作のRadiko録音アプリ「Radirec」で録音しためたファイルに対し、条件リストをもとにファイル作成日時をてがかりに番組判定を行います。

条件リストはこんな感じに……番組名、放送曜日、開始時刻、終了時刻のセットです。

property progList : {{“日曜天国”, Sunday, “10:00″, “11:55″}, {“深夜の馬鹿力”, Tuesday, “01:00″, “03:00″}, {“ジブリ汗まみれ”, Sunday, “23:00″, “23:30″}}

rad1.jpg

もともと、録音アプリケーション(Radirec)のほうでこうした処理をしておけばよかったのですが、最低限の機能だけで安定して動作すればいいやぐらいで作ったので……あとで苦労しているわけで。

年末年始は寝て過ごしていたので、ちょっとプログラミングのカンが鈍ってしまい、ちょっとしたリハビリがわりにつくってみたというところでしょうか。

a reference toによるアクセス高速化ではなく、別Scriptのpropertyに対してアクセスするタイプの高速化を行っています。あんまり効き目のなさそうなところにも使っていますが、AppleScriptObjCでの高速化のための練習、みたいな感じでしょうか。

これまでのサブルーチンはAppleScript Studioに入れられることを前提に作ってきましたが、これからはAppleScriptObjCを前提に作る必要があります。

rad2.jpg

録り貯めたファイルのうち、ほとんどは処理できたものの、一部ファイルの判定は行えなかったので、まだ納得できていないレベルです。

スクリプト名:作成日時からラジオ録音番組名を設定
–スピードアップ記述の練習用に(意味もないのに)プロパティを別Scriptオブジェクトに分けてみた
script speedUp
  –ファイル一覧のハンドリング用
  
property fList : {}
  
  
–区分けする番組リスト(番組名、放送曜日(開始時刻のみ判定)、開始時刻、終了時刻
  
property progList : {{“日曜天国”, Sunday, “10:00″, “11:55″}, {“深夜の馬鹿力”, Tuesday, “01:00″, “03:00″}, {“ジブリ汗まみれ”, Sunday, “23:00″, “23:30″}}
  
  
–処理対象ファイルの拡張子リスト
  
property extList : {“mov”, “mp3″, “m4a”}
  
end script

–録音日時が日付をまたがないことが処理条件
–もうちょっと機能アップしないと不十分?

set falseList to {} –処理できなかったファイルの一覧が入る

set tFol to choose folder with prompt “処理対象フォルダを指定してください”

tell application “Finder”
  –指定フォルダ内のファイル一覧を取得(指定フォルダ以下のすべてのフォルダ内を走査)
  
try
    set (fList of speedUp) to entire contents of tFol as alias list
  on error
    display dialog “Error” buttons {“OK”} default button 1 with icon 2
    
return
  end try
end tell

–メインループ

repeat with i in (fList of speedUp)
  –set j to contents of i
  
set aInfo to info for i
  
  
–ファイル拡張子で処理対象を判別
  
tell application “Finder”
    set aExt to name extension of aInfo
    
–log aExt
    
if aExt is in (extList of speedUp) then
      
      
–作成日時と作成曜日を取り出す
      
set sDate to creation date of aInfo
      
–log sDate
      
      
set yNum to year of sDate
      
set dayNum to weekday of sDate as number
      
set monthNum to month of sDate as number
      
set dateNum to day of sDate
      
      
–番組リストとの照合
      
set hitF to false
      
repeat with ii in progList of speedUp
        set {pName, sWeekday, sTime, eTime} to ii
        
        
if (sWeekday as number) = dayNum then
          –開始時刻のdate objectを求める
          
set s1Time to sDate
          
set {h1Num, m1Num} to words of sTime
          
set h1Num to h1Num as number
          
set m1Num to m1Num as number
          
set hours of s1Time to h1Num
          
set minutes of s1Time to m1Num
          
set s1Time to s1Time - (10 * 60) –開始時刻を10分前倒しで判定
          
          
–終了時刻のdate objectを求める
          
set e1Time to sDate
          
set {h2Num, m2Num} to words of eTime
          
set h2Num to h2Num as number
          
set m2Num to m2Num as number
          
set hours of e1Time to h2Num
          
set minutes of e1Time to m2Num
          
set e1Time to e1Time + (10 * 60) –終了時刻を10分後ろ倒しで判定
          
          
          
if s1Time sDate and sDate e1Time then
            –ファイル名指定用の数値データを桁数指定しつつ文字列化
            
set yStr to retZeroPaddingText(yNum, 4) of me
            
set mStr to retZeroPaddingText(monthNum, 2) of me
            
set dStr to retZeroPaddingText(dateNum, 2) of me
            
set targStr to pName & ” “ & yStr & ” “ & mStr & “月” & dStr & “日.” & aExt –ここを変更するとファイル名のフォーマットが変わる
            
            
set name of i to targStr –ファイルの名称変更
            
            
set hitF to true
            
            
exit repeat
            
          end if
        end if
      end repeat
      
      
if hitF = false then
        set the end of falseList to (contents of i)
      end if
      
    else
      set the end of falseList to (contents of i)
    end if
  end tell
end repeat

return falseList

–数値にゼロパディングしたテキストを返す
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

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

12/29 ファイル作成曜日に応じてラベルを付ける

指定フォルダ内の全ファイルのファイル作成日を調べ、指定曜日に作成されたものにラベルを振るAppleScriptです。

Radikoのタイマー録音を行う自作のAppleScriptObjCアプリケーションで、いろんな番組を録り貯めていたのですが……録り貯めた膨大なファイルの中から特定の番組だけを抽出するために、作成したものです。

label0.jpg

lebel.jpg

▲伊集院光「深夜の馬鹿力」(月曜日25:00〜27:00……つまり、「火曜日」)を抽出したところ。

label2.jpg

スクリプト名:ファイル作成曜日に応じてラベルを付ける
set aFol to choose folder with prompt “処理対象のファイルが入っているフォルダを選択”

set aList to {“日曜日”, “月曜日”, “火曜日”, “水曜日”, “木曜日”, “金曜日”, “土曜日”}
set aMes to “ラベルを付ける対象曜日を選択してください。”
set targDay to retNumberFromChooseFromList(aList, aMes) of me

tell application “Finder”
  tell folder aFol
    set aList to every file as alias list
  end tell
end tell

repeat with i in aList
  set aInfo to info for i
  
set sDate to creation date of aInfo
  
set dayNum to weekday of sDate as number
  
  
if dayNum = targDay then
    tell application “Finder”
      set label index of i to 2 –赤いラベル
    end tell
  end if
end repeat

–リストからの選択ダイアログで、選択したアイテムのアイテムナンバーを返す
on retNumberFromChooseFromList(aList, aMes)
  set aRes to choose from list aList with prompt aMes
  
if aRes = false then return false
  
set aRes to (contents of aRes) as string
  
set itemCount to 1
  
repeat with i in aList
    set j to contents of i
    
if j is equal to aRes then
      return itemCount
    end if
    
set itemCount to itemCount + 1
  end repeat
end retNumberFromChooseFromList

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

10/18 指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v3

バンドルIDを指定してアプリケーションのパスを求め、その中のローカライズ文字列テーブルから指定ラベルに該当する文字を取り出すAppleScriptの改良版です。

プロセスを確認して、起動中であればプロセスから情報を取得。起動中ではない場合には、Finder経由で実行ファイルのパスを求めるようにしています。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v3

set aRes to retLocalizedStringFromApp("135.006", "com.apple.itunes") of me
–> "ライブラリ"–Japanese
–> "LIBRARY"–English
–> "BIBLIOTHÈQUE"–French
–> ""–Simply Chinese
–> "資料庫"–Traditional Chinese
–> "MEDIATHEK"–Deutsch

–指定バンドルIDのアプリケーション内のResourcesフォルダの中の現在のロケールのフォルダ内のLocalizable.strings内の指定タグに対応する値を取得
–iTunesのような「不適切なローカライズ」に対応するために、リソース内のローカライズデータからオブジェクト名を取得
on retLocalizedStringFromApp(locLabel, bundleID)
  
  
set pRes to retExistenceOfProcessByBundleID(bundleID) of me
  
  
if pRes is not equal to false then
    –指定Bundle IDのプロセスが起動していた場合
    
tell application "System Events"
      tell pRes
        set appFile to application file
      end tell
    end tell
    
  else
    –指定Bundle IDのプロセスが起動していなかった場合
    
tell application "Finder"
      try
        set appFile to application file id bundleID
      on error
        return
      end try
    end tell
    
    
set appFile to appFile as alias
  end if
  
  
  
set aStr to localized string locLabel in bundle appFile
  
end retLocalizedStringFromApp

–指定のバンドルIDのプロセスが起動していればプロセスへの参照を返す、なければfalseを返す
on retExistenceOfProcessByBundleID(bundleID)
  tell application "System Events"
    set aProc to every process whose bundle identifier is equal to bundleID
    
if aProc = {} then return false
    
    
set aProc to contents of first item of aProc
    
return aProc
  end tell
end retExistenceOfProcessByBundleID

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

本ルーチンを使って、iTunesの「ライブラリ」に該当する文字列を取り出すテストを行い、実際に使用ユーザー環境の言語を変更してログインし直し、各言語で動作確認を行ってみました。

スクリプト名:iTunes_control_Japanese
tell application “iTunes”
  tell source “ライブラリ”
    tell playlist “ライブラリ”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_English
tell application “iTunes”
  tell source “LIBRARY”
    tell playlist “LIBRARY”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_Deteuch
tell application “iTunes”
  tell source “MEDIATHEK”
    tell playlist “MEDIATHEK”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_French
tell application “iTunes”
  tell source “BIBLIOTHÈQUE”
    tell playlist “BIBLIOTHÈQUE”
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_Chinese (simplified)
tell application “iTunes”
  tell source
    tell playlist
      count every track
    end tell
  end tell
end tell

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

スクリプト名:iTunes_control_Chinese (traditional)
tell application “iTunes”
  tell source “資料庫”
    tell playlist “資料庫”
      count every track
    end tell
  end tell
end tell

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

……で、冒頭のScriptを使うと、これらの各言語環境ごとにバラバラのオブジェクト名を記述しなければならなかった部分が、1本のScriptでカバーできるはずです。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v3.1
–すべての言語環境でこのプログラムに統一できるはず
set aRes to retLocalizedStringFromApp(“135.006″, “com.apple.itunes”) of me

tell application “iTunes”
  tell source aRes
    tell playlist aRes
      count every track
    end tell
  end tell
end tell

–指定バンドルIDのアプリケーション内のResourcesフォルダの中の現在のロケールのフォルダ内のLocalizable.strings内の指定タグに対応する値を取得
–iTunesのような「不適切なローカライズ」に対応するために、リソース内のローカライズデータからオブジェクト名を取得
on retLocalizedStringFromApp(locLabel, bundleID)
  
  
set pRes to retExistenceOfProcessByBundleID(bundleID) of me
  
  
if pRes is not equal to false then
    –指定Bundle IDのプロセスが起動していた場合
    
tell application “System Events”
      tell pRes
        set appFile to application file
      end tell
    end tell
    
  else
    –指定Bundle IDのプロセスが起動していなかった場合
    
tell application “Finder”
      try
        set appFile to application file id bundleID
      on error
        return
      end try
    end tell
    
    
set appFile to appFile as alias
  end if
  
  
  
set aStr to localized string locLabel in bundle appFile
  
end retLocalizedStringFromApp

–指定のバンドルIDのプロセスが起動していればプロセスへの参照を返す、なければfalseを返す
on retExistenceOfProcessByBundleID(bundleID)
  tell application “System Events”
    set aProc to every process whose bundle identifier is equal to bundleID
    
if aProc = {} then return false
    
    
set aProc to contents of first item of aProc
    
return aProc
  end tell
end retExistenceOfProcessByBundleID

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

10/18 指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v2

指定アプリの内部リソースから指定ラベルに該当する文字列を取り出すAppleScriptの改良版です。アプリケーション名を指定してプロセスを取得するのではなく、Finderに対してアプリケーションのバンドルIDを指定してアプリケーションの実行ファイルのパスを求めるようにして処理するものです。

ただ、Mac OS X 10.6上だとFinderへのAppleScriptからのアクセスが途中からとても遅くなってしまったので、なんでもかんでもFinderに問い合わせるのは避けたいところです。

スクリプト名:指定アプリの指定タグの文字列をアプリ内のLocalizableStringsから取得する v2

set aRes to retLocalizedStringFromApp("135.006", "com.apple.itunes") of me

on retLocalizedStringFromApp(locLabel, appID)
  
  
tell application "Finder"
    try
      set appFile to application file id appID
    on error
      return
    end try
  end tell
  
  
set appFile to appFile as alias
  
  
set aStr to localized string locLabel in bundle appFile
  
end retLocalizedStringFromApp

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

04/25 ファイルのファイル名を求める

ファイルのファイル名を求めるAppleScriptです。

このぐらいだと、書くのに10秒とかそのぐらいの難易度ですが……あるMac系のプログラマの方(それなりに経験の長い方)がAppleScriptでファイル名を求める方法について、テキストを分解して云々と書かれているのを見て衝撃を受けました。

本Blogでは、たいていのサブルーチンがAppleScript Studio環境でも動くように動作確認しているものが多く、最近ではAppleScriptObjCのプロジェクトの中に放り込んでも動くことを確認している(サブルーチン呼び出し時の「of me」を削除することが必要)ケースもぼちぼちあります。

通常のAppleScript環境では動いても、AppleScript Studio環境では動かないようなものもあるため、仕方なく対策のために書き直しているものも多々あります。

とくに、ファイルからファイル名を求めるという処理は、通常のAppleScript環境では「瞬殺」レベルの簡単なものですが、AppleScript Studio環境ではかなり手を焼かされました。

……パスをテキストとして評価してparseするような処理をいろいろ掲載していますが、Finderに名前を問い合わせるという「基本」が前提です。少し、基本的な処理記述例もしつこく掲載しておくべきなのかもしれません。

振り返ってみると、過去に出版されていたAppleScriptの入門書と呼ばれるものでも、掲載されているサンプルのAppleScriptは……正直、いただけないものが多かったので……素直な記法で書き直して掲載しておいたほうがよいのかもしれません。

スクリプト名:ファイルのファイル名を求める
set aFile to choose file

tell application “Finder”
  set aName to name of aFile
end tell

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

03/20 英語+数字連番フォルダをインクリメントして新規作成

選択中のフォルダ中に存在するアルファベットの単語(なんでも可)+連番の数字からなるフォルダの数字の並びから推測して、インクリメント(+1)した数字を持つフォルダを新規作成するAppleScriptです。

Script Menuに登録して使うことを前提に作ってみました。

fin_1.jpg

のような状態で実行すると……

fin_2.jpg

のように、通し番号を+1ふやしたフォルダを作成します。プログラムの開発作業を行いつつ、テストデータの出力先フォルダを新たに作って作業を行うようなときに使いました。

一応、番号部分を取り出してソートを行い、数字的に見て一番大きなものを検出して「最新の数字」を推測していますが、そもそも既存のフォルダ名称に「No.1 work1」のように複数の数字が登場するようなパターンは考慮していません。使用の際には注意が必要です。

スクリプト名:英語連番フォルダをインクリメントして新規作成
set aaSel to getFinderSelection() of me
if aaSel = false then return

tell application "Finder"
  
  
tell folder aaSel
    set nList to name of every folder
  end tell
  
  
set aList to {}
  
repeat with i in nList
    set j to contents of i
    
    
set aRes to retNumCharOnly(j) of me
    
try
      set aRes to aRes as number
    on error
      display dialog "選択されたフォルダ中には、連番の「アルファベット」+「数字」形式のフォルダはないようです。" buttons {"OK"} default button 1 with icon 1 with title "選択中フォルダ内のフォルダ名エラー"
      
return
    end try
    
    
set the end of aList to {aRes, j}
    
  end repeat
  
end tell

–フォルダ名を昇順ソート
set bList to shellSortListAscending(aList, 1) of me
set bLastItem to last item of bList
set {numItem, folName} to bLastItem
set numItemStr to numItem as string

–新規フォルダ名称に用いるべき数字を計算(+1)する
set numItemIncrement to numItem + 1
set numItemIncrementStr to numItemIncrement as string

–元のフォルダ名称から、数字部分を新規のものに差し替える
set newFolName to repChar(folName, numItemStr, numItemIncrementStr) of me

–得られたフォルダ名称で新規作成
tell application "Finder"
  make new folder at folder aaSel with properties {name:newFolName}
end tell

–与えられた文字列から、数字部分だけを返す
on retNumCharOnly(a)
  set aList to characters of a
  
  
set aResList to {}
  
  
set inF to false –アイテムへの取り込みフラグ:初期値=false(取り込まない)
  
set oneItem to ""
  
  
repeat with i in aList
    set j to contents of i
    
set aF to detectOutNumChar(j) of me –aF:現在のキャラクタがNumericかどうかの判定フラグ
    
    
if aF = true and inF = false then
      set inF to true
      
set oneItem to oneItem & j
      
    else if aF = true and inF = true then
      set oneItem to oneItem & j
      
    else if aF = false and inF = true then
      set the end of aResList to oneItem
      
set oneItem to ""
      
set inF to false
      
    else if aF = false and inF = false then
      –なにもしない
      
    end if
  end repeat
  
  
if oneItem is not equal to "" then
    set the end of aResList to oneItem
  end if
  
  
return aResList
  
–> {"100", "12", "88"}
end retNumCharOnly

–数字範囲外の文字があるかどうかをテストする
–数字の文字以外のものが入っていたらfalse
on detectOutNumChar(testText)
  –ANK文字列(大文字小文字は問わない)
  
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 detectOutNumChar

–シェルソートで入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) > (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListAscending

–シェルソートで入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) < (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListDecending

–文字置換ルーチン
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

–Finderで選択中のフォルダを取得する
on getFinderSelection()
  tell application "Finder"
    try
      set aSel to selection as alias
    on error
      set aSel to {}
    end try
    
    
if aSel is not equal to {} then
      return aSel –selectionが存在していた場合
      
    else
      –念のため、FinderのWindowが1枚も開いていない可能性について検証しておく
      
set wCount to count every window
      
if wCount = 0 then return false –なんにもWindowが存在していなかったらfalseを返す
      
      
tell front window –「window 1」 と同じ
        –カラム表示/アイコン表示/リスト表示/カバーフロー表示の場合で共通
        
set aSel to target as alias
      end tell
    end if
  end tell
end getFinderSelection

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

03/20 Finderで選択中のフォルダを取得する

Finderで選択中のフォルダを取得するAppleScriptです。

Finder上で選択中のファイルなりフォルダを対象にして処理を行うというのは、AppleScriptではよくある処理というか……あまりにも当たり前すぎて興味の対象にすらならない感がありますが、よくよく考えてみると……

fin_icon_1.jpg

のような状態というのは、何かが選択されているのでselectionを取得できるわけですが、

fin_icon_2.jpg

のような状態でも、一応ウィンドウで表示している対象が選択されている、といえなくはありません。

そこで、このような状況も考慮して「選択中のフォルダ」を返すルーチンを作ってみました。ただし……副作用もあって、複数のフォルダが選択されている状態を無視してその1階層上のフォルダを返すとか、そもそもファイルが選択されている状態は考慮していないとか、かなり用途が限られてくるものです。

スクリプト名:Finderで選択中のフォルダを取得する
set fRes to getFinderSelection() of me

–Finderで選択中のフォルダを取得する
on getFinderSelection()
  tell application "Finder"
    try
      set aSel to selection as alias
    on error
      set aSel to {}
    end try
    
    
if aSel is not equal to {} then
      return aSel –selectionが存在していた場合
      
    else
      –念のため、FinderのWindowが1枚も開いていない可能性について検証しておく
      
set wCount to count every window
      
if wCount = 0 then return false –なんにもWindowが存在していなかったらfalseを返す
      
      
tell front window –「window 1」 と同じ
        –カラム表示/アイコン表示/リスト表示/カバーフロー表示の場合で共通
        
set aSel to target as alias
      end tell
    end if
  end tell
end getFinderSelection

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

03/08 aliasのリストをファイルの作成日でソートして返す

与えられたaliasのリストを各ファイルの作成日でソートして古い順に返すAppleScriptです。

ドラッグ&ドロップすると指定のプリンタにInDesignから印刷を行うAppleScriptのドロップレットを書いて使ってみたら、プリンタに送られる順番が目茶苦茶になってしまいました。

あとから印刷結果を手でソートすることほどむなしいことはありません。

そこで、ドロップレット用にファイルの作成日時でソートするサブルーチンを、汎用ルーチンの寄せ集めで作った次第です。

find1.jpg

こんな風にFinder上でファイルを選択しておいて本Scriptを実行すると、作成日時が古い順にソートして返してくれます。AppleScriptから数百ファイルもドキュメントを生成して、印刷しなければならないような場合でも、作成日時の古い順から印刷してくれます。

のんびりしていそうな割には、切実なニーズを満たすために作成したものだったりします。

スクリプト名:aliasのリストをファイルの作成日でソートして返す
tell application "Finder"
  set aSel to selection as alias list
end tell

–ファイル作成日でソート(古いものから新しいものへ)
set aliasRes to sortAliasByCreationDate(aSel) of me

–> {alias "Cherry:Users:maro:Documents:AppleScript:MacJournalで選択中のjournal entryのBlog公開ステータスを取得する.scpt", alias "Cherry:Users:maro:Documents:AppleScript:目に見えるプロセス一覧を取得する.scpt", alias "Cherry:Users:maro:Documents:AppleScript:最前面のアプリケーションを取得する.scpt", alias "Cherry:Users:maro:Documents:AppleScript:InDesignの文字置換機能を用いた文字置換.scpt", alias "Cherry:Users:maro:Documents:AppleScript:aliasのリストをファイルの作成日でソートして返す.scpt"}

on sortAliasByCreationDate(aliasList)
  
  
tell application "Finder"
    set aList to {}
    
    
repeat with i in aliasList
      set j to contents of i
      
set the end of aList to {j, creation date of j}
    end repeat
    
    
set cList to shellSortListAscending(aList, 2) of me –で作成日時でソート
    
    
    
set aliasList to {}
    
set fnCount to 1
    
repeat with i in cList
      set j to contents of (item 1 of i)
      
      
set the end of aliasList to j
    end repeat
  end tell
  
  
return aliasList
  
end sortAliasByCreationDate

–シェルソートで入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) > (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListAscending

–シェルソートで入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
  set n to length of a
  
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
  
repeat with h in cols
    if (h (n - 1)) then
      repeat with i from h to (n - 1)
        set v to item (i + 1) of a
        
set j to i
        
repeat while (j h) and ((contents of item keyItem of item (j - h + 1) of a) < (item keyItem of v))
          set (item (j + 1) of a) to (item (j - h + 1) of a)
          
set j to j - h
        end repeat
        
set item (j + 1) of a to v
      end repeat
    end if
  end repeat
  
return a
end shellSortListDecending

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

02/22 選択した項目を新規フォルダに移動

Finderで選択中の項目を新規フォルダに移動するAppleScriptです。

説明文を書いたり画面キャプチャを撮る時間のほうがプログラム作成の数十倍の時間がかかるという(困った)代物です。

まちがいなく「組み捨て」レベルで保存すらする価値がないものですが、そういうものでも必要な人がいるというリサーチを行い、試しに組んでみました。

まずは、Finder上でファイルを選択。

scrn1.jpg

この状態で本スクリプトを実行すると……フォルダの選択を求められます。

scrn2.jpg

フォルダ選択ダイアログには新規フォルダ作成のボタンがついているため、ここで新規作成ボタンを押すと選択中のフォルダの中に新規フォルダを作成できます。

scrn3.jpg

すると……新規フォルダの中にさきほど選択していたファイルが移動しているのが分かります。

scrn4.jpg

……あまり、何かが激しく便利になったり、作業効率が向上したりすることはないようですが…………

スクリプト名:選択した項目を新規フォルダに移動
set newFol to choose folder with prompt “移動先のフォルダを選択してください。”

tell application “Finder”
  set aList to selection as alias list
  
move aList to folder newFol
end tell

beep

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

12/29 指定フォルダ容量をMB単位で返す_v2

Finder上で選択したフォルダの容量をMB単位で返すAppleScriptです。

容量が大きい場合に結果が指数表示になってしまっていたため、duコマンドのパラメータを変更してみました。

また、Mac OS X 10.6からはディスク容量を1024ではなく1000で繰り上がるように計算するようになったので、本サブルーチン(=duコマンド)の結果とFinderの結果は異なります。

概算のために用意したので自分としてはこれで大丈夫ですが、気になる方はduコマンドからバイト単位で結果を取得して計算するとよいでしょう。

スクリプト名:指定フォルダ容量をMB単位で返す_v2
tell application “Finder”
  set aSel to selection –as alias list–10.4.11で効かなかった。びっくりした
  
if aSel = {} then
    display dialog “Finder上で何も選択されていません。” buttons {“OK”} default button 1 with icon 1
    
return
  end if
  
  
set aaSel to first item of aSel
  
set aaSel to aaSel as alias
  
end tell

set aMBsize to getFolderSizeByMB(aaSel) of me

–指定フォルダのalias以下の容量をMBで返す
on getFolderSizeByMB(aFolAlias)
  set aDir to (POSIX path of aFolAlias)
  
set aDir to quoted form of aDir
  
  
try
    –set aRes to do shell script “du -k -d 0 ” & aDir
    
set aRes to do shell script “du -m -d 0 “ & aDir
  on error
    return
  end try
  
  
set aList to words of aRes
  
set aSize to (first item of aList)
  
  
return aSize
  
end getFolderSizeByMB

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

12/29 指定フォルダ容量をMB単位で返す

指定フォルダの容量を求めるAppleScriptです。

単純にシェルのduコマンドを呼び出しているだけで、しかも指定するのはフォルダでなくてもよいのですが、フォルダ内の容量取得を目的として作成したものです。

Finder上で何らかのフォルダを選択した状態で本AppleScriptを実行してください。

ファイルサーバー上の指定フォルダを処理する際に、一定容量以上のサイズのフォルダの場合には「大きすぎる」とメッセージを出して処理を行わないようにすることを検討。その判断のために本サブルーチンを作成しました。

微妙に、duコマンドの「Kバイト」(1024で桁上がり)とMac OS X 10.6上のKバイト(1000で桁上がり)の間に差があって、Finder上の結果と異なる数字になるようですが、概算で取得できればよいのでこんなものだと思っています。

スクリプト名:指定フォルダ容量をMB単位で返す
tell application “Finder”
  set aSel to selection –as alias list–10.4.11で効かなかった。びっくりした
  
if aSel = {} then
    display dialog “Finder上で何も選択されていません。” buttons {“OK”} default button 1 with icon 1
    
return
  end if
  
  
set aaSel to first item of aSel
  
set aaSel to aaSel as alias
  
end tell

set aMBsize to getFolderSizeByMB(aaSel) of me

–指定フォルダのalias以下の容量をMBで返す
on getFolderSizeByMB(aFolAlias)
  set aDir to (POSIX path of aFolAlias)
  
set aDir to quoted form of aDir
  
  
try
    set aRes to do shell script “du -k -d 0 “ & aDir
  on error
    return
  end try
  
  
set aList to words of aRes
  
set aSize to (first item of aList) as number
  
  
set mSize to aSize / 1024
  
return mSize
  
end getFolderSizeByMB

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

12/06 Finder上で選択中のフォルダをdiskimageに(パスワード指定つき)

Finderで選択中のフォルダをdiskimageファイル(ディスクイメージ)にするAppleScriptです。diskimageファイルには任意のパスワードを指定できます。

スクリプト名:Finder上で選択中のフォルダをdiskimageに(パスワード指定つき)
property aPassword : "piyopiyo"

tell application "Finder"
  set aSel to selection as alias list
  
if aSel = {} then
    display dialog "Finder上で何も選択されていません。" buttons {"OK"} default button 1 with icon 1
    
return
  end if
  
  
set aaSel to first item of aSel
  
set fRes to detectFolder(aaSel) of me
  
  
if fRes = false then
    display dialog "Finder上でフォルダが選択されていません。" buttons {"OK"} default button 1 with icon 1
    
return
  end if
end tell

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 aCMD to "printf ‘" & aPassword & "’ | hdiutil create -encryption -srcfolder " & aDir & " " & (quoted form of (fp2 & fn & ".dmg"))
set fp3 to do shell script aCMD

–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 = "フォルダ")
end detectFolder

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

10/29 指定フォルダ以下のファイルやフォルダからラベルを外す

指定フォルダ以下のすべてのファイルやフォルダからラベルを外すAppleScriptです。

再帰で処理すると遅いし、spotlightで検索して処理するのも(できるけど)かったるいし……ということで、entire contentsですべての要素を取得してループです。

entire contetnsへの参照(a reference to)に対して一括で命令する方法もあるのですが、AppleScript側は全対象に向けて一括で指令を出してすぐに処理が終了するものの……Finder側の処理がすぐには終わらないので(実際に試しました)、こんなもんでいいんじゃないかと。

スクリプト名:指定フォルダ以下のファイルやフォルダからラベルを外す
global fList, fList_r

set aFol to choose folder

tell application "Finder"
  set fList to entire contents of aFol as alias list
end tell
set fList_r to a reference to fList

tell application "Finder"
  repeat with i in fList_r
    ignoring application responses
      set label index of i to 0
    end ignoring
  end repeat
end tell

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

10/26 フォルダ差分コピー

指定した2つのフォルダ(A、B)のフォルダを比較して、フォルダAにあってフォルダBにないフォルダを、フォルダBに対してコピーします。

まとめてフォルダをコピーしている最中に、エラーなどで途中でコピーが中断されたような場合に、残りのフォルダをコピーするように作成した「作り捨て」レベルのAppleScriptです。

スクリプト名:フォルダ差分コピー
set aFol to choose folder with prompt "フォルダAを選択してください。"
set bFol to choose folder with prompt "フォルダBを選択してください。"

tell application "Finder"
  tell folder aFol
    set aList to name of every folder
  end tell
  
tell folder bFol
    set bList to name of every folder
  end tell
end tell

set aHasNotBList to {}
repeat with i in aList
  set j to contents of i
  
if j is not in bList then
    set the end of aHasNotBList to j
  end if
end repeat

set bHasNotAList to {}
repeat with i in bList
  set j to contents of i
  
if j is not in aList then
    set the end of bHasNotAList to j
  end if
end repeat

if aHasNotBList is not equal to {} then
  display dialog "フォルダAにあってBに存在しないもの:" & return & list2RETURNseparatedText(aHasNotBList) of me
end if

tell application "Finder"
  repeat with i in aHasNotBList
    set origFol to folder i of folder aFol
    
try
      duplicate origFol to folder (bFol as alias)
    end try
  end repeat
end tell

(*
if bHasNotAList is not equal to {} then
  display dialog "フォルダBにあってAに存在しないもの:" & return & list2RETURNseparatedText(bHasNotAList) of me
end if
*)

–リストをタブ区切りのテキストに変換
on list2RETURNseparatedText(aList)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to return
  
set bList to aList as string
  
set AppleScript’s text item delimiters to curDelim
  
return bList
end list2RETURNseparatedText

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

08/07 エイリアス書類からオリジナルファイルの情報を取得する

エイリアス書類からオリジナルファイルの情報を取得するAppleScriptです。

スクリプト名:エイリアス書類からオリジナルファイルの情報を取得する
set aFile to choose file

tell application "Finder"
  try
    set origI to (original item of aFile) as alias
  on error
    –エイリアス書類のオリジナルファイルが削除されてた場合にはエラーになる
    
set origI to false
  end try
end tell

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

07/03 ファイル名Aの拡張子を、ファイル名Bの拡張子に付け替える

ファイル名Aの拡張子を、ファイル名Bの拡張子に付け替えるAppleScriptです。

fn1.jpg

まず、1つのHTMLファイル(拡張子=.html)を選択。

fn2.jpg

次いで、JPEGファイル(拡張子=.jpg)を選択すると・・。

最初に選択したファイルの拡張子を、後で選択したファイルの拡張子に置き換えた文字列が得られます。お好みに応じて、実際にファイル名のリネームを行ったりするとよいかもしれません。

スクリプト名:ファイル名Aの拡張子を、 ファイル名Bの拡張子に付け替える
set aFile to choose file
set bFile to choose file

tell application “Finder”
  set aName to name of aFile –> iChatで文字チャットの相手に文字列を送信。長い場合にはzip圧縮して送信.html
  
set bName to name of bFile –> xcframew1.jpg
end tell

set cName to cnvExtFromAtoB(aName, bName) of me
–> “iChatで文字チャットの相手に文字列を送信。長い場合にはzip圧縮して送信.jpg”

–ファイル名Aの拡張子を、ファイル名Bの拡張子に付け替える
on cnvExtFromAtoB(aFileName, bFilename)
  set aExt to retExtNameFromFilenameStr(aFileName) of me
  
set bExt to retExtNameFromFilenameStr(bFilename) of me
  
set nFileName to repChar(aFileName, aExt, bExt) of me
  
return nFileName
end cnvExtFromAtoB

–ファイル名文字列から拡張子のみ取得する
on retExtNameFromFilenameStr(fileNameStr)
  set fLen to length of fileNameStr
  
set revText to (reverse of (characters of fileNameStr)) as string –逆順テキストを作成
  
set anOffset to offset of “.” in revText
  
set fRes to text (fLen - anOffset + 1) thru -1 of fileNameStr
  
return fRes
end retExtNameFromFilenameStr

–文字置換ルーチン
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

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

06/06 ファイルのコピー(通常実行、非同期高速実行)

ファイルのコピーを行うAppleScriptです。

通常の記述例と、非同期実行(ignoring application responces)による高速実行の両方を書いておきます。

ファイルコピーの動作は、ファイルのサイズ(巨大なファイルのコピーには時間がかかります)や、ネットワーク回線の太さ(遅い回線の上にあるサーバーのファイルをコピーするには時間がかかります)に依存します。もちろん、実行するマシンの処理速度にも影響を受けます。

ファイルコピー動作がその後の処理に影響を及ぼさない(コピーしたファイルを対象とした動作を行わない)のであれば、非同期実行の指定を行ってしまうのもひとつの手です。ただし、非同期実行を行った場合には、コピー中にエラーが発生(容量オーバーなど)した場合でもそのエラーに対処することはできません。

スクリプト名:ファイルのコピー
set a to choose file with prompt "コピーするファイルを選択"
set b to choose folder with prompt "コピー先のフォルダを選択"

–通常コピー
tell application "Finder"
  duplicate a to b with replacing –with replacingは、同名のファイルがあった場合に上書きする指定
end tell

–処理終了を待たずに次の処理へ(非同期実行)
ignoring application responses
  tell application "Finder"
    duplicate a to b with replacing
  end tell
end ignoring

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

06/06 ファイル名を変更する

ファイル名を変更するAppleScriptです。もう、このあたりになるといちいち保存するレベルではなく、「組み捨て」ですが、たまに質問が来たりするので掲載を。

Finderでさまざまなファイル操作を行う方法については、やや「Finder独自な」やりかたが多いので、まとめておくとよいのかもしれません。

スクリプト名:ファイル名を変更する
set a to choose file –aliasが取得される
set b to (text returned of (display dialog "新しいファイル名を入力:" default answer "")) –とりあえずダイアログから入力しているが、普通こんなのんびりしたことはやらない

tell application "Finder"
  set name of a to b –ファイル名を変更する
end tell

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

05/27 マウント中のdiskimage中のファイルをすべて削除

マウント中のdiskimageの全フォルダ階層を走査して、ファイルが存在したら削除する……というAppleScriptです。

まずは……どうしてこんなものを作ったのかといえば、いくつもファイルサーバーもマウントして、データ内容から出力先のファイルサーバーを自動選択してファイルコピーするような(割と大きめの……数千行オーダーの)AppleScriptのプログラムを作っていました。

ところが、実環境ではファイルサーバーが運用されているものの、同じ環境を再現できなかったので、マウント状態だけでも再現しようと思い立ち、実環境の名称と同じドライブをマウントしている状態を作り出すために、sparseimage(可変容量)のdisk imageを作成して、デスクトップにマウントしていました。

マウントした状態でプログラムを実行し、出力状態などを評価していたわけですが……ファイル出力状況を確認したら、また元に戻さなければなりません。

元のdisk imageをアーカイブしてオリジナルの状態で保存しておいてもよかったのですが、ちょっと容量が大きかったのと作業中のドライブの残量が少なかったので、オリジナルのdisk image(のコピー)を取っておくのはいかがなものか、という話に。

そこで、マウント中のdisk imageの全階層を走査(entire contents)してファイルをリストアップし、削除するというAppleScriptを作成した次第です。

ejectableなdiskをdisk imageとみなしているので、もしかしたらUSBメモリなどもマウントしていたら、一緒に削除してしまうかもしれませんが……USBメモリはあらかじめ抜いておくということで対処していました。

disk imageのみをリストアップする、というプログラムは、なかなかに奥が深そうなので後日リトライしてみたいところです。

スクリプト名:diskimage中のファイルをすべて削除
–disk imageをリストアップする
tell application "Finder"
  set dList to every disk whose ejectable is true
end tell

repeat with i in dList
  set j to contents of i
  
deleteInsideFolder(j) of me
end repeat

on deleteInsideFolder(a)
  tell application "Finder"
    set fList to entire contents of a as alias list
  end tell
  
  
set aList to {}
  
repeat with i in fList
    set j to contents of i
    
set aClass to (info for j)
    
set bClass to folder of aClass
    
    
if bClass = false then
      set the end of aList to j
    end if
  end repeat
  
  
tell application "Finder"
    delete aList
    
–empty trash
  end tell
end deleteInsideFolder

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

02/04 指定されたファイルのparentにラベルとコメントを付ける

指定されたファイルの親フォルダに指定のラベルと指定のコメントを付けるAppleScriptです。

実に簡単な内容で、あまり多くの人が気にも止めない内容に見えるのですが、AppleScript的な世界観における重要度はかなり高い処理です。下手をすると、高速ソートルーチンよりも重要かもしれません。

本処理は、さまざまなファイルを大量に処理するようなケースで、かつ、データが各フォルダに分けられて入っている(InDesignの書類とか)ようなケースを想定しています。そして、フォルダ内のデータにエラーが発生した場合には、親フォルダにラベルをつけて色を変え、さらにエラー原因をコメントとして残しておく、ためのものです。

こうした処理が入っているかどうかでツール系のScriptの使い勝手は大きく変わってくるため、「必須」を通り越して「ないとおかしい」というレベルのものです。さらに、Finder上で新規Windowを作成して、エラー対象ファイル/フォルダを選択状態にしておくとか……そうした処理は、ぜひやっておきたいものです(大量にあると困りますけれど)。

スクリプト名:指定されたファイルのparentにラベルとコメントを付ける
set aFile to choose file
set aComment to “エラーだぴよー”
setLabelAndCommentToParentFol(aFile, aComment) of me

–指定されたファイルの親フォルダにラベルとコメントを付ける
on setLabelAndCommentToParentFol(aFile, aComment)
  tell application “Finder”
    set aParent to (parent of aFile) as alias
    
set label index of aParent to 4 –ぶるーのラベル
    
set comment of aParent to aComment
  end tell
end setLabelAndCommentToParentFol

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

12/22 指定フォルダの中のフォルダをオープン

Finder上で選択しているフォルダの中に入っているフォルダをオープンします。

Script Menuに入れて使っています。正確にいえば、選択中のフォルダの1階層下にあるフォルダをすべてオープンします。「指定フォルダ中のファイルを消してフォルダだけ残す」AppleScriptで処理をしたフォルダに対して、再度Windowを並べるために実行するものです。

スクリプト名:指定フォルダの中のフォルダをオープン
tell application "Finder"
  set a to selection
  
set aa to first item of a
  
set aaa to aa as alias
  
  
tell folder aaa
    tell every folder to open
  end tell
end tell

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

12/22 指定フォルダ中のファイルを消してフォルダだけ残す

Finder上で選択中のフォルダの中に入っているものの中から、フォルダだけ残してファイルを消去するAppleScriptです。

単純作業を行っていたときに、あまりに数が多かったのでその場で組んで使いました。Script Menuに入れて使うようにしています。Finderのdeleteコマンドで、1つのファイルを対象にするのではなく、ファイルを入れたリスト型変数を対象にすることで、一気にファイルのdelete(ゴミ箱に移動)することができます。

何種類かのデータの画面のスナップショットを撮っていて、それぞれ別のフォルダに手で移動させていました。何種類かに分ける必要があったので、複数のWindowをひらいて作業していました。ファイルの移動作業をしやすくするために、FinderのWindowをきれいにならべてファイル移動。

……これをいくつものデータに対して行っていたのですが、Windowの位置とかフォルダ名などはそのまま使い回したかったので、一度作業したフォルダ(=Window)をまるごとコピーして、中に入っている画面キャプチャファイル「だけを」消去できると都合がよかったのです。しかも、指定階層以下のすべての階層にあるやつを。

そこで、本Scriptを作成して作業を手っ取り早く終わらせました。日常的な作業の効率化を行うためには、その不毛さ加減を体感するために一度自分の手でやってみることが重要だと思います。同じ単純作業ばかりやっていると頭痛がしてくるので、すぐにAppleScriptで自動化したくなること請け合いです。

スクリプト名:指定フォルダ中のファイルを消してフォルダだけ残す
tell application “Finder”
  set a to selection
  
set aa to first item of a
  
set aaa to aa as alias
  
set aList to entire contents of aaa as alias list
  
  
set deleteList to {}
  
repeat with i in aList
    set j to contents of i
    
set aKind to kind of j
    
if aKind is not equal to “フォルダ” then –change here on another language environment. This means “folder”
      set the end of deleteList to j
    end if
  end repeat
  
  
if deleteList is not equal to {} then
    delete deleteList –これで一括消去
  end if
end tell

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

08/01 指定フォルダ内の指定種別(kind)のファイル一覧を取得

指定のフォルダ内にある指定種別(kind)のファイル一覧を取得するAppleScriptをいろいろ掲載します。

まずは、指定したいファイルがどのような種別になっているのかを確認する必要があります。

  set a to choose file
  set aInfo to info for a

こんなAppleScriptを実行すると、結果として……

–> {name:”元の位置にペースト.key”, creation date:date “2009年 7月 30日 木曜日 11:07:15 AM”, modification date:date “2009年 7月 30日 木曜日 5:10:57 PM”, size:803112, folder:false, alias:false, package folder:false, visible:true, extension hidden:true, name extension:”key”, displayed name:”元の位置にペースト”, default application:alias “Cherry:Applications:iWork ‘09:Keynote.app:”, kind:”Keynote 書類”……}

などと返ってきますので、「ああ、『Keynote 書類』って指定すればいいんだ!」と分ります。属性によっては、whoseで指定できないものもあるので、そのあたりが要注意です。

スクリプト名:指定フォルダ内の指定形式のファイル一覧を取得(原始的手法)
指定フォルダ内の指定形式のファイル一覧を取得(原始的手法)
set aFol to choose folder

tell application Finder
  tell folder aFol
    set indList to (every file whose kind is Keynote 書類“)
  end tell
end tell

> {document file “a reference toのスコープ範囲 のバックアップ.key” of folder “AppleScript” of folder “Documents” of folder “maro” of folder “Users” of startup disk of application “Finder”, document file “a reference toのスコープ範囲.key” of folder “AppleScript” of folder “Documents” of folder “maro” of folder “Users” of startup disk of application “Finder”, document file “AppleScript past now and future のバックアップ.key” of folder “AppleScript” of folder “Documents” of folder “maro” of folder “Users” of startup disk of application “Finder”, (省略)}

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

何も考えないで書くとこんな感じでしょうか。ただ、これだと結果がdocumentファイルのリストで返ってくるので、後で何か処理しようとしたときに面倒です。aliasに変換するのがベストなので……

スクリプト名:指定フォルダ内の指定形式のファイル一覧を取得(近代的手法)
set aFol to choose folder

tell application Finder
  tell folder aFol
    set indList to (every file whose kind is Keynote 書類“) as alias list
  end tell
end tell

>  {alias “Cherry:Users:maro:Documents:AppleScript:a reference toのスコープ範囲 のバックアップ.key”, alias “Cherry:Users:maro:Documents:AppleScript:a reference toのスコープ範囲.key”, alias “Cherry:Users:maro:Documents:AppleScript:AppleScript past now and future のバックアップ.key:”, alias “Cherry:Users:maro:Documents:AppleScript:AppleScript past now and future.key:”, alias “Cherry:Users:maro:Documents:AppleScript:AppleScript Studioの歴史.key:”,(中略)}

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

と、as alias listでcastすると、いい感じにaliasのlistで結果が返ってきます。

しかし、これでも……ファイル名の次に作成日時、拡張子……など、さまざまな情報を取得したいと思ったら、再度同じような処理を書かなくてはなりません。

スクリプト名:指定フォルダ内の指定形式のファイル一覧を取得(現代的手法)
set aFol to choose folder

tell application Finder
  tell folder aFol
    set indList to a reference to (every file whose kind is Keynote 書類“)
  end tell
  
set namList to name of indList
end tell

> {”a reference toのスコープ範囲 のバックアップ.key”, “a reference toのスコープ範囲.key”, “AppleScript past now and future のバックアップ.key”, “AppleScript past now and future.key”, “AppleScript Studioの歴史.key”, “attribute runの書式取得 のバックアップ.key”, “attribute runの書式取得.key”, “boot sequence difference.key”, “Dylan Grand Tour.key”, “Expression MediaのScripting資料.key”, “FontBookに関する情報.key”…(省略)}

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

このようにして、a reference toで指定条件に合致するオブジェクト(ファイル)への参照を変数に入れておけば、そこからファイル名や作成日時などを自由に取り出せるようになります。

実用上は、「動けば別になんでもいい」ところですが、ちょっとしたこだわりの処理で、クソ面白くもなんともない(AppleScriptの実力がぜんぜん発揮されない)ファイル処理がちょっとだけ楽しくなったら、素敵なことではないでしょうか。

01/10 Finderの最前面のパスをTerminalで開く(強化ver5, Leopard対応)

Mac OS X 10.4の時代に作ったScriptが、10.5になって動かなくなっていたのに気付き、修正を行いました(以前のバージョンは、10.4であれば問題なく動きます)。
(more…)

12/20 指定フォルダにある特定の書類種別(複数)のファイルのリストを取得。エイリアスで

特定フォルダに存在するファイルのうち、ファイルのkind(書類種別)を複数指定し、それに該当するファイルをエイリアスのリストとして取得する記述例です。
(more…)

12/20 指定フォルダにある特定のラベル(複数)のファイルのリストを取得。エイリアスで

よくあるファイル処理で……特定フォルダに存在しているファイルのうち、指定の複数のラベルがついたものを、エイリアスのリストで取得するというものです。
(more…)

05/29 フォルダ同士の内容比較

指定した2つのフォルダに入っているファイル(ファイル名)を比較して、差分を表示します。

スクリプト名:フォルダ同士の内容比較
set aFol to choose folder with promptフォルダAを選択してください。
set bFol to choose folder with promptフォルダBを選択してください。

tell applicationFinder
  tell folder aFol
    set aList to name of every file
  end tell
  
tell folder bFol
    set bList to name of every file
  end tell
end tell

set aHasNotBList to {}
repeat with i in aList
  set j to contents of i
  
if j is not in bList then
    set the end of aHasNotBList to j
  end if
end repeat

set bHasNotAList to {}
repeat with i in bList
  set j to contents of i
  
if j is not in aList then
    set the end of bHasNotAList to j
  end if
end repeat

if aHasNotBList is not equal to {} then
  display dialogフォルダAにあってBに存在しないもの:” & return & list2RETURNseparatedText(aHasNotBList) of me
end if

if bHasNotAList is not equal to {} then
  display dialogフォルダBにあってAに存在しないもの:” & return & list2RETURNseparatedText(bHasNotAList) of me
end if

リストをタブ区切りのテキストに変換
on list2RETURNseparatedText(aList)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to return
  
set bList to aList as string
  
set AppleScript’s text item delimiters to curDelim
  
return bList
end list2RETURNseparatedText

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