Archive for the 'ファイル処理(file)' 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/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

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

08/07 AppleScript中にファイルパスを記述する

いろいろ質問が寄せられていたり、US Appleのメーリングリストでも投稿数を統計的に分析(数えるだけ)すると明らかに傾向が出ています。AppleScriptに関する初心者の質問のほとんどがファイルパスに関するものです。

dd5.jpg

AppleScript上でのパスの書き方、扱い方については以下の記事を参照してください。ここでは、楽に記述する方法(作業方法)について述べます。

■AppleScriptで扱う「パス」について(1)
■AppleScriptで扱う「パス」について(2)
■AppleScriptで扱う「パス」について(3)
■AppleScriptで扱う「パス」について(4)

とくに、Mac OS Xでは(10.2あたりから?)ローカライズド・ファイルシステムが採用されているので、Finderで見ているとおり「デスクトップ」などとフォルダ名を書きたくなるところですが、実際の名前とは異なる(本当のフォルダ名は英語で「Desktop」)ためAppleScriptにエラーを返されたりと、使いやすさの実現のために実装されている機能のかずかずが仇になることもあるようです。

そこで、AppleScriptのプログラム中にファイルパスを記述する簡単な方法をご紹介しましょう。たいして難しくもなければ、悩ましいこともありません。単なる「作業」でしかありません。

やりかたは、大きくわけて2つ(私は(2)しか使いませんが、、、)。

(1)ドラッグ&ドロップ コース

Finder上でパスを調べたいファイルを選択して、AppleScriptエディタの記述エリアにそのままドラッグ&ドロップします。

dd1.jpg

すると、POSIX pathがAppleScriptエディタに入るので……

dd2.jpg

これをそのまま使用してみましょう。

スクリプト名:パスの書き方1
set a to “/Users/maro/Desktop/ScriptingBridgeFramework.pdf”
set aPath to (a as POSIX file)

–> file “Cherry:Users:maro:Desktop:ScriptingBridgeFramework.pdf”

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

こんな感じでパスを取得できます。fileのままだと受け付けないアプリケーションも多いので、「as alias」でalias(ファイル参照)にcastしてから使うとなおよいでしょう。

スクリプト名:パスの書き方1
set a to “/Users/maro/Desktop/ScriptingBridgeFramework.pdf”
set aPath to (a as POSIX file) as alias

–> alias “Cherry:Users:maro:Desktop:ScriptingBridgeFramework.pdf”

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

(2)コピー&ペースト コース

なにげにAppleScriptエディタ上に1行だけ書いて実行。ファイルのパスを求めたいときには「choose file」を、フォルダのパスを求めたい場合には「choose folder」とだけ書いて実行すればOKです。

dd3.jpg

実行してファイルを選ぶと「結果」欄にファイルのパスが表示されるので、

dd4.jpg

おもむろにパスの前後についているダブルクォートで囲まれている部分まで選択して、コピー。

別のScript(パスを書いておきたいScript)にペーストしてそのまま使用。

まあこんなもんでしょう。ただし、as aliasでファイル参照情報に変換する際に、参照先のファイルが存在しない(消したとか、名前を変更したとか)場合にはエラーになるので、try〜end tryのエラートラップを仕掛けて実行するのが大人な書き方です。

もっと「大人な」書き方をすれば、「path to」でホームディレクトリの位置を求めて、そこから相対的にどの位置にあるかといった情報を計算(文字列としてただつなぐだけ)して求めることになりますが、単に自分だけが使う「使い捨てScript」でそれほど気を使う必要もない、ということであれば……このような記述でも手っ取り早くてよいのではないでしょうか。

別のユーザー環境では動かないこと必至(HDD名称やユーザー名が違う)なので、こういうラフな書き方をしたAppleScriptは他人に配布しないように注意してください。あるいは、property文でプログラムの冒頭にまとめて書いて定義しておいて、他人の環境ではそこを直すようにコメントしておくとか。

スクリプト名:パスの書き方2
set b to “Cherry:Users:maro:Desktop:ScriptingBridgeFramework.pdf”
set bPath to b as alias

–> alias “Cherry:Users:maro:Desktop:ScriptingBridgeFramework.pdf”

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

07/10 子番号を考慮しつつ、新しいファイル名を返す

特定のフォルダ内のファイル名リストをもとに、指定のファイルを新規作成可能か(重複がないか)判断を行い、重複がある場合にはアンダースコア(「_」)のあとに子番号を補ったファイル名を生成。子番号つきのファイルがすでに存在する場合には、そのうち一番大きな番号のものを検出して、さらに新しい子番号つきのファイル名を返すAppleScriptです。

既存フォルダへのファイルのコピーなどの際に用いる、かなり高機能なルーチンです。はっきり言って上級者向けのものであり、初心者向けのものではありません。

特定のフォルダ内に、

  ”RIMG0056.JPG”, “RIMG0056_1.JPG”

というファイルが存在しており、そこに、

  ”RIMG0056.JPG”

というファイルを新規にコピーしようとした際に、ファイル名の重複を検出し、さらに子番号のうち最大のものを検出して、

  ”RIMG0056_2.JPG”

というファイル名を返します。

スクリプト名:子番号を考慮しつつ、新しいファイル名を返す

set myName to “RIMG0056.JPG”
–set aList to {”RIMG0056.JPG”, “RIMG0056_1.JPG”, “RIMG0056_2.JPG”}
set aList to {“RIMG0056.JPG”, “RIMG0056_1.JPG”}

set my2Name to retChildFileName(myName, aList) of dupNameGenKit

script dupNameGenKit
  –子番号を考慮しつつ、新しいファイル名を返す
  
on retChildFileName(myName, aList)
    
    
set numList to {}
    
–set aList to {”RIMG0056.JPG”}
    
    
repeat with i in aList
      set j to contents of i
      
      
set tmpN to offset of “_” in j
      
if tmpN is not equal to 0 then
        set tmpA to text (tmpN + 1) thru -1 of j
        
set aOfst to offset of “.” in tmpA
        
set numStr to text (tmpN + 1) thru (tmpN + aOfst - 1) of j
        
        
set the end of numList to (numStr as number)
      end if
      
    end repeat
    
    
if numList is not equal to {} then
      –すでに「_」の子番号が存在する場合
      
set b to shellSortDecending(numList) of me
      
set largestNum to contents of first item of b
      
      
set largestNum to largestNum + 1
      
    else
      –まだ「_」の子番号が存在しない場合
      
set largestNum to 1
      
    end if
    
    
set pureName to retNameFromFilenameStr(myName) of me
    
set anExt to retExtNameFromFilenameStr(myName) of me
    
set gName to pureName & “_” & (largestNum as string) & anExt
    
    
return gName
    
  end retChildFileName
  
  
  
–ファイル名文字列から拡張子を外して返す
  
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
  
  
–ファイル名文字列から拡張子のみ取得する
  
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 shellSortAscending(a)
    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 (j - h + 1) of a) > 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 shellSortAscending
  
  
–シェルソートでリストを降順ソート(入れ子ではないリスト)
  
on shellSortDecending(a)
    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 (j - h + 1) of a) < 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 shellSortDecending
end script

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

07/09 SIGMA Raw画像からメーカーと機種名を取り出す v2

SIGMAのデジカメで撮影したRAW画像ファイル(拡張子「.X3F」)を分析して、内包しているEXIFデータから「メーカー名+機種名」の文字列情報を取り出すAppleScriptです。

本ScriptでSIGMAのRAW画像ファイルを処理すると「SIGMA DP1」などのメーカー名+モデル名の文字列を、取得できなかった場合にはFalseを返します。

写真家の友人から「たまった写真データを機種別にフォルダ分けして、ファイル名の重複があった場合には連番でリネームするAppleScriptを作って〜」と、頼まれて物々交換でAppleScriptを作ったときに、JPEGファイルについてはImage EventsやsipsコマンドでEXIF情報にアクセスできるのですが、肝心のSIGMAのRAWデータだけはなぜかEXIF情報が取得できないことが判明。

インターネット上でデジカメメーカー各社のRAWファイルをかき集め、CANNONの「CR2」、OLYMPUSの「ORF」、富士フィルムの「RAF」、リコーの「DNG」、ニコンの「NEF」などひととおりsipsでEXIF情報にアクセスできることを確認。

SIGMAがマイナーなマニアックなメーカーであるために、Mac OS X 10.6.xが標準でSIGMA RAWの解析機能を持っていないことが原因であることが判明しました。

そこで、仕方なくAppleScriptでSIGMAのRAWファイルを解析。どうせRAW画像ファイルといっても、EXIFの情報を内包していることは予想でき、しかもまともな技術者ならEXIF情報はファイルの先頭の方に置いておくはず。

stringsコマンドで文字列らしきところを文字ダンプ。あっさりと先頭の方にEXIF情報が見つかりました。

さらに、ファイル全体に対して実行すると数十メガバイト分も処理することになって面倒(時間がかかる)なので先頭の数十行分だけしか処理しないようにして試してみました。

他社のRAW画像はおおかたMac OS Xが標準で解析できるので、本AppleScriptはあくまでSIGMAのRAW画像解析専用です。

スクリプト名:SIGMA Raw画像からメーカーと機種名を取り出すテスト v2
set a to choose file with prompt “Please Select Raw File”
set aRes to getCameraNameFromSIGMArawfile(a) of me

–SIGMAのRawファイルを解析してメーカー名+機種名を取り出す
on getCameraNameFromSIGMArawfile(aFile)
  set aPOSIX to POSIX path of aFile
  
  
ignoring case
    if aPOSIX does not end with “.X3F” then
      return false
    end if
  end ignoring
  
  
  
–Raw画像ファイルを文字ダンプして先頭から40行取り出す
  
set sText to “/usr/bin/strings “ & quoted form of aPOSIX & ” | head -n 40″
  
set aRes to do shell script sText
  
  
set aList to paragraphs of aRes
  
set aLen to length of aList
  
  
–Exifっぽい部分をサーチ
  
set aMaker to “”
  
set aMakerModel to “”
  
  
repeat with i from 1 to aLen
    set j to contents of item i of aList
    
if j contains “Exif” then
      set aMaker to contents of item (i + 1) of aList
      
set aMakerModel to contents of item (i + 2) of aList
      
exit repeat
    end if
  end repeat
  
  
–含んでいなかった場合(T_T)
  
if aMaker = “” then
    return false
  end if
  
  
–結果表示
  
return aMakerModel
  
end getCameraNameFromSIGMArawfile

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

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/27 指定のテキストをAppleScriptとしてコンパイルし、実行可能なアプレットとして出力する

指定のテキストをAppleScriptとしてosacompileコマンドでコンパイルし、実行可能なアプレット(ドロップレット)として指定パスに保存するAppleScriptです。

テキストから実行可能なアプリケーションを生成する場合には、AppleScriptエディタ(スクリプトエディタ)を外部からAppleScriptでコントロールするやり方をよく使ってきました。手あかがつくほど使った方法なので、信頼性も高く、あえて同じことを別のやり方でできるように準備しておく必要は(本来は)ありません。

しかし、Appleが将来的な方針を明らかにしない以上、何らかの方針転換を行った場合に備えておくことも必要です。たいていの(重要な)処理は複数のやり方で実現できるように、下調べをしてあります。その一環として、このサブルーチンを作ることにしました。

Mac OS X 10.6でosacompileコマンドに実行ファイル作成機能が付加されたため、これを使って指定のテキストからバイナリを作成できるようにしてみました。

休みの日にテレビを見ながら作っていたので、ひどく散漫なコードになってしまい、無駄な処理なども残っているかもしれません。ただ、期待どおりの動作は行うようなのでとりあえずこんなもので。

osacompileコマンドのアプレットの出力パス指定ではずいぶん手間どらされました。出力先をフルパスで指定してもうまく動作せず、cdコマンドとの合わせ技でなんとか。

スクリプト名:指定のテキストをAppleScriptとしてコンパイルし、実行可能なアプレットとして出力する
set asText to “on run
tell application \”Finder\”
beep
display dialog \”test\”
beep
end tell
end run

on open(aPath)

end

set asFile to choose file name
set asRes to makeASexecutable(asText, asFile) of me

if asRes is not equal to true then
  display dialog asRes
  
return
end if

–指定のテキストをAppleScriptとしてコンパイルし、実行可能なアプレットとして出力する
on makeASexecutable(aText, outPathAlias)
  
  
–出力先のaliasからファイル名のみ撮り出す
  
set aStr to outPathAlias as string
  
set fnRes to getLastLayerOfDirData(aStr) of me
  
  
–指定のファル名に拡張子が適切に付いていない場合には補う
  
if fnRes does not end with “.app” then
    set fnRes to fnRes & “.app”
  end if
  
  
–テンポラリフォルダ内のテキストファイルに書き出す
  
set aFileName to (do shell script “uuidgen”) & “.applescript”
  
set tmpAppName to (do shell script “uuidgen”) & “.app”
  
  
set aTempFol to path to temporary items folder from system domain
  
set aTempFolPosix to (POSIX path of aTempFol) & aFileName
  
  
set aTempPathText to (aTempFol as string) & aFileName
  
write_to_file(aText, aTempPathText, false) of me
  
  
–ファイルキャッシュをHDDにシンクロさせる
  
–do shell script “sync”–> 実行しなくても大丈夫だった
  
  
–osacompileコマンドでアプレットを生成
  
set sText to “cd “ & (quoted form of POSIX path of aTempFol) & ” && osacompile -s -x -o “ & fnRes & ” “ & aFileName
  
try
    –コンパイル時にアプリケーションの起動を待ったりする可能性があるので、待ち時間を1時間に設定
    
with timeout of 3600 seconds
      do shell script sText
    end timeout
  on error erMes
    return erMes
  end try
  
  
  
–テンポラリに書き込んだTextのAppleScriptを消す
  
try
    do shell script “rm -f “ & quoted form of aTempFolPosix
  end try
  
  
  
–生成したアプレットを指定のフォルダに移動する
  
set origAppPath to POSIX path of ((aTempFol as string) & fnRes)
  
set destPath to POSIX path of getOnlyFolder(aStr) of me & fnRes
  
  
try
    do shell script “mv -f “ & quoted form of origAppPath & ” “ & quoted form of destPath
  on error erMes
    return erMes
  end try
  
  
return true
  
end makeASexecutable

–テキストで与えられたパスデータから、フォルダのみを返す
on getOnlyFolder(a)
  set curDelim to AppleScript’s text item delimiters
  
set AppleScript’s text item delimiters to {“:”}
  
set aList to text items of a
  
set bList to items 1 thru -2 of aList
  
set aText to bList as string
  
set AppleScript’s text item delimiters to curDelim
  
set aText to aText & “:”
  
return aText
end getOnlyFolder

–テキストで与えられたパスデータから、最終階層のテキストのみを返す
on getLastLayerOfDirData(aData)
  set aColon to “:” as Unicode text
  
copy aData to bData
  
if bData ends with “:” then
    set bData to text 1 thru -2 of bData
  end if
  
  
set aLen to length of bData
  
set rData to reverse of (characters of bData)
  
set rData to rData as string
  
set dPos to offset of aColon in rData
  
set resData to text (aLen - dPos + 2) thru -1 of bData
  
return resData
  
end getLastLayerOfDirData

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

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

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

08/06 指定フォルダ内にエイリアス書類を作成

指定フォルダ以下にあるXcodeプロジェクト書類をspotlightでリストアップし、別途指定した出力先フォルダにエイリアス書類を出力するAppleScriptです。

「com.apple.xcode.project」の部分を書き換えれば、お好きな書類をリストアップ可能です。

alias1.jpg

エイリアス書類をAppleScriptから作成することは、(自分は)めったにないのですが……たとえば、何らかの条件に合致するファイル群(あるいは多量のパス情報)を抽出したとして、そのエイリアス書類を特定のフォルダに作成して入れておくと、いちいちテキストを見ながらFinder上で指定フォルダに移動してファイルをオープン……といった煩雑な処理をしなくて済みます。

ただ、実戦でもそこまでやることは少ないので、エイリアス書類をAppleScriptから作成するケースは非常に少ないのですが、やり方を再確認しておこうと考え、ちょっと書いてみました。

エイリアス書類を作成するのに、「make new alias file」で作成しています。以前(Classic Mac OS時代)には異なる記法だったような気がするのですが、もはやClassic Mac OSを使うこともないので気にしないことに。

エイリアス書類の作成コマンドと、エイリアス書類のファイル名が重複してしまった場合の回避処理がみどころです。ただし、ファイル名重複時の回避処理はそれほど気合いが入っておらず、同名のファイルが256個以上出力される場合にはエラーになります。そこは、256以上の数値に変えてみるか……抜本的に重複回避処理を見直してみたほうがよいでしょう。

スクリプト名:指定フォルダ内にエイリアス書類を作成
set aFol to choose folder with prompt "エイリアスファイルを出力するフォルダを選択"
set bFol to choose folder with prompt "Xcode書類を探すフォルダを選択"

set bList to getFileListWithSpotLight("kMDItemContentType", "com.apple.xcode.project", bFol) of me –Xcodeのファイルをクリエータコードで検索
repeat with i in bList
  set aFolStr to aFol as string
  
makeAliasFileInAFolder(i, aFolStr) of me
end repeat

–指定フォルダ内に指定名称のエイリアス書類を作成する
on makeAliasFileInAFolder(anAlias, outFol)
  tell application "Finder"
    set aName to name of anAlias
    
tell folder outFol
      if file aName exists then
        set c to makeUniqueName(outFol, aName) of me
      end if
    end tell
    
    
set newalias to make new alias at folder outFol to anAlias
    
set name of newalias to aName
  end tell
end makeAliasFileInAFolder

–指定フォルダ下に存在できる、指定名称+数字の名前の(かぶらない)ファイル名を作成
on makeUniqueName(aFolder, origName)
  set pureFileName to retFileNameWithoutExt(origName) of me
  
set anExt to retExtNameFromFilenameStr(origName) of me
  
  
tell application "Finder"
    tell folder aFolder
      repeat with i from 1 to 256
        if not (exists of file (pureFileName & " " & (i as string) & "." & anExt)) then
          return (pureFileName & " " & (i as string) & "." & anExt)
        end if
      end repeat
    end tell
  end tell
end makeUniqueName

–ファイル名から拡張子を外す
on retFileNameWithoutExt(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 retFileNameWithoutExt

–ファイル名文字列から拡張子のみ取得する
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

–指定階層下で、指定クリエータコードのファイルを取得(Mac OS X 10.4.x以上で動作)
on getFileListWithSpotLight(aMetaDataItem, aParam, startDir)
  set sDirText to quoted form of POSIX path of startDir
  
set shellText to "mdfind ‘" & aMetaDataItem & " == \"" & aParam & "\"’ -onlyin " & sDirText
  
try
    set aRes to do shell script shellText
  on error
    return {}
  end try
  
set pList to paragraphs of aRes
  
set aList to {}
  
repeat with i in pList
    set aPath to POSIX file i
    
set aPath to aPath as alias
    
set the end of aList to aPath
  end repeat
  
return aList
end getFileListWithSpotLight

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

07/25 指定フォルダ以下のファイル作成日付をファイル修正日にコピーする

指定フォルダ以下のすべてのファイルの作成日付の情報を取得し、最終修正日の情報にコピーするAppleScriptです。

10数年前に撮影したQuickTake 100のデジタル写真データをPICTからJPEGにコンバートしたのはよかったのですが、iPhotoにインポートしたときに作成日が反映されなかったので、ためしに作ってみました。

なお、実行のためには、Developper Toolsがインストールしてある必要があります。

これでダメなら、本当にEXIFのデータをいじくる必要が(汗)

スクリプト名:指定フォルダ以下のファイル作成日付をファイル修正日にコピーする
set aFol to choose folder
set fList to {}
set f_r to a reference to fList

–外付けHDDをSpotlightの処理対象外に指定していたので、mdfindコマンドを使わなかった
tell application “Finder”
  set fList to entire contents of aFol as alias list
end tell

–メインループ
repeat with i in f_r
  set j to contents of i
  
try
    set aInfo to info for j
    
set aF to folder of aInfo
  on error
    set aF to false
  end try
  
  
if aF = false then
    changeModDateToCreationDate(j) of me
  end if
end repeat

–作成日付の情報を修正情報にコピーする
on changeModDateToCreationDate(aFile)
  tell application “Finder”
    set aInfo to info for aFile
    
set creDate to creation date of aInfo
  end tell
  
set aDateStr to makeMMDDYYYYhhmmssStr(creDate) of me
  
  
set aP to POSIX path of aFile
  
  
try
    do shell script “/usr/bin/SetFile -m “ & quoted form of aDateStr & ” “ & quoted form of aP –修正日
  end try
end changeModDateToCreationDate

–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

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

07/21 ファイル作成日付を変更する

ファイル作成日付および最終変更日を変更するAppleScriptです。

AppleScriptからFinderをコントロールしても作成日/変更日は変更できないため、shellコマンドを呼び出してくることになります。

Developper Toolsをインストールすると一緒に入ってくるSetFileコマンド(/usr/bin/SetFile)を呼び出します。Developper Toolsをインストールしていない環境ではSetFileがそもそも存在していないので、本Scriptを実行しても日付の変更は行われません。

昔に撮りためたQuickTake 100の写真データをコンバートしようとして、QuickTake PICTをGraphic Converterでオープンできることを確認したのですが、作成日付に当時のもの(15年ぐらい昔)を残しておきたいと思い立ち、作成日の変更方法を調べてみた次第です。

スクリプト名:ファイル作成日付を変更する
set a to choose file with prompt "作成日付の情報をピックアップするファイルを選択してください"
tell application "Finder"
  set aInfo to info for a
  
set creDate to creation date of aInfo
end tell
set aDateStr to makeMMDDYYYYhhmmssStr(creDate) of me

set b to choose file with prompt "日付情報を変更するファイルを選択してください"
set bP to POSIX path of b

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

–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

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

06/24 指定フォルダ内をすべて削除し、そのフォルダも削除

指定フォルダ内のファイルをすべて削除し、指定フォルダ自体も削除するAppleScriptです。

本当は、Finderに命令して指定フォルダをゴミ箱に捨てて(delete)、ゴミ箱をカラにすれば(empty trash)4行で一丁上がりなのですが………………Finder経由で命令すると音が出ていやだとか、ゴミ箱をカラにするのが嫌われるとか(汗)、そういう状況に対応するためのものです。

スクリプト名:指定フォルダ内をすべて削除し、そのフォルダも削除
set a to choose folder
deleteFolderItself(a) of me

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

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

06/24 指定データをZip圧縮

指定文字列をテキストファイルに書き出して、さらにZip圧縮して返すAppleScriptです。

ありもののファイルを処理するのではなく、文字列データをファイルに書き出してZip圧縮します。

スクリプト名:指定データをzip圧縮
set aRes to do shell script "cd /usr/bin && ls -la"
makeZipFile(aRes) of me
–> "/private/var/folders/UG/UG9cHtbG2Rabs++1YwYvY++++TU/TemporaryItems/B5009213-2C00-46DB-9FF6-17C9BC26FD16.txt.zip"

–指定データをzip圧縮
on makeZipFile(aStr)
  set aPath to (path to temporary items from system domain) as string
  
set afN to (do shell script "uuidgen") & ".txt"
  
  
set aFullPath to aPath & afN
  
write_to_file(aStr, aFullPath, false) of me
  
  
set f1Path to quoted form of POSIX path of aFullPath
  
set f2Path to quoted form of POSIX path of (aFullPath & ".zip")
  
  
try
    with timeout of 3600 seconds
      set aRes to do shell script "/usr/bin/zip -r -j " & f2Path & " " & f1Path
    end timeout
  on error
    return false
  end try
  
  
return (POSIX path of (aFullPath & ".zip"))
end makeZipFile

–ファイルの追記ルーチン「write_to_file」
–追記データ、追記対象ファイル、boolean(trueで追記)
on write_to_file(this_data, target_file, append_data)
  try
    set the target_file to the target_file as text
    
set the open_target_file to open for access file target_file with write permission
    
if append_data is false then set eof of the open_target_file to 0
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
return true
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
end write_to_file

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

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/05 指定フォルダをtarでまとめる

指定フォルダをtarでまとめるAppleScriptです。

指定のフォルダを渡すと、指定フォルダと同じ階層に指定フォルダ名でtarアーカイブを作成します。オリジナルのフォルダは削除せず、そのまま残しておきます。エラー時にはfalseが、正常動作時にはtarアーカイブへのaliasが返ります。

一般的には、フォルダをアーカイブする場合にはZipコマンドで圧縮してまとめたほうが手っ取り早いところですが、対象のファイルが巨大(数百Mバイトオーダー、数Gバイトオーダー)である場合などは「圧縮」するのが大変です。さらに、そもそも圧縮されているデータ(ムービーや画像)なので「再圧縮する意味がない」という場合もあります。

そこで、圧縮せずに単に「1ファイルにまとめる」tarアーカイブを用いた方が便利なケースがあります。本AppleScriptはそのために作成したものです。ただし、tarアーカイブにまとめるファイルには、日本語のファイル名やフォルダ名を使った場合に「展開時にファイル名を戻せない」といった問題(そもそもtarがそういう仕様)があるため、英数字のみのファイル名を使用するなどの注意が必要です。

tarは、語源が「Tape ARchive」であるとおり、HDDの内容をテープストリーマ(バックアップ装置)に転送するために、複数のファイルをまとめて1つのtarファイルにして磁気テープに書き出すためのものです。ExabyteのDATストリーマーなどをUNIXワークステーションで使ったことはありますが、さすがにMac OS X環境で磁気テープストリーマを使ったことはありません、、、

スクリプト名:指定フォルダをtarでまとめる
set a to choose folder
set b to tarFolder(a) of me

–指定フォルダをtarでまとめる
on tarFolder(a)
  set anAlias to a as alias
  
  
tell application “Finder”
    set aParent to parent of anAlias
    
set aFolName to name of anAlias
  end tell
  
  
set aParent to aParent as alias
  
  
set preCMD to “cd “ & quoted form of POSIX path of aParent
  
set tarCMD to “tar cvf “ & quoted form of (aFolName & “.tar”) & ” “ & quoted form of (aFolName & “/”)
  
  
try
    set aRes to do shell script (preCMD & ” && “ & tarCMD)
  on error
    return false
  end try
  
  
  
tell application “Finder”
    set tarAlias to ((aParent as string) & aFolName & “.tar”) as alias
    
set tarEx to exists of tarAlias
  end tell
  
  
if tarEx = true then
    return tarAlias
  else
    return false
  end if
end tarFolder

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

02/23 Mac OS X 10.5/10.6上のファイル名/フォルダ名に関するバグ

AppleScriptにおける「パス」について(5)のコメント欄で教えていただいた件を実際に確認してみました。

asbug1.jpg

濁点つき(たぶん、半濁点も)のフォルダを用意して(たぶん、ファイルでも同様)……そのファイル名を取得。ファイル名の1文字目のidを調べると、文字+濁点(or 半濁点)に分離してIDが取得されてしまうというものです。

スクリプト名:AS_bug_check
set aFol to choose folder

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

set anID to id of first character of aName

–「ふつうのFolder」を選択した場合
–> 12405

–「だくてんテスト」を選択した場合
–> {12383, 12441}–> 「た」+濁点

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

通常、1文字に対応する値が返ってくるところで、リストで2文字分返ってきてしまいます。それぞれ、文字コードの内容をUnicode Checkerで調べてみると……

asbug2.jpg

asbug3.jpg

ご覧のとおりです。

asbug4.jpg

Finderから取得したファイル名/フォルダ名の文字数をカウントする分には大丈夫そう(↑)なのですが……

asbug5.jpg

ファイル名を1文字ずつ分解して(characters of)、IDを取得するとごらんのとおり(↑)です。

02/17 AppleScriptにおける「パス」について(5)

もしも、現在お使いの環境がMac OS X 10.4.11などの古い環境(Mac OS X 10.5より前)の場合には、Mac OS Xのバグについても考慮しておく必要があります。

Mac OS X 10.5以前は、フォルダ名に濁点や半濁点を含む文字列があった場合……

  例:ぴよぴよ(半濁点を含む)
  例:びっくり(濁点を含む)

ファイル名/フォルダ名をFinderから取得して文字ごとに取り出すような処理をすると、「濁点と文字が分離されてしまう」というバグがありました。

filename.jpg

▲「Webログ」フォルダを選択した場合の実行結果(Mac OS X 10.4.11)

長い間、US Appleの担当者に散々文句を言って、ようやく10.5で直った次第です(ただ、その一方で10.5以降ではカタカナと平仮名の区別ができなくなるというおそるべきバグが……)。

回避方法は、一度stringにcastしてからunicode textにcastする、というものです。ものすごく、意味不明な処理を書かなくてはならず、本当にイライラするところですが……動かないよりはマシということで、長年この記述を行ってきました。いまでも、Mac OS X 10.4.11上で動作させる必要のあるAppleScriptは、そのような処理を書いています。

02/17 AppleScriptにおける「パス」について(4)

Mac OS X上でパスを記述する際に、気をつけるべき点があります。それが、ローカライズド・フォルダ。基本的かつ重要なフォルダについては、それぞれの言語環境に合わせてローカライズした名前をユーザーに見せる仕組みがローカライズド・フォルダですが……裏を返せば、Finder上で見えてる名前と本当の名前が違う場合がある、というわけです。

ふだん見ている「書類」や「デスクトップ」といったフォルダ名は、本当のフォルダ名ではありません。Finder上でカスタムアイコンが付いているようなフォルダは軒並みローカライズド・フォルダで表示されており、実際には「Documents」とか「Desktop」という名前がついています。

このあたり、AppleScript上でパスを記述する際に問題になるかもしれません(普段から英語で表記していたので、その存在を忘れていました)。

「フォルダの本当の名前」を確認するのに一番よいのは、Terminal.appを起動して確認するとか……あるいは、ちょっとしたAppleScriptを記述して

  set a to choose folder

実際にAppleScriptから「本当の名前」を確認してみることです。

02/17 AppleScriptにおける「パス」について(3)

昨今のOSはほとんどそうですが、Mac OS XはマルチユーザーのOS(複数ユーザーの使用を前提としたOS)であるため、ユーザーごとにホームディレクトリが異なります。また、Finder上でハードディスクの名前もユーザーが自由に変えられるようになっています。

このため、ホームディレクトリへのパスや、その他の重要なフォルダへのパスについても、プログラム上に直接文字列で書いておくと、他のマシンや他のユーザー環境で実行できなくなってしまいます。

そこで、途中までのパスについてはコンピュータからpath to命令で取得し、その後のパスのみ文字列で書いておき、それらを結合するというのが一般的なパスの記述方法です。

set picFol to path to pictures folder from user domain
–> alias “Cherry:Users:maro:Pictures:”

さらに、上記サンプルで出てきていますが、「ドメイン」の概念が必要になります。
たとえば、「ライブラリ」フォルダというものは、

  Macintosh HD:システム:ライブラリ:
  Macintosh HD:ライブラリ:
  Macintosh HD:Users:hiyoko:ライブラリ:

の3種類があって、それぞれ「system domain」、「local domain」、「user domain」のドメイン指定によって指定できます。

スクリプト名:ライブラリフォルダを各ドメインで取得
set libFol to path to library folder from system domain
–> alias "Macintosh HD:System:Library:"

set libFol to path to library folder from local domain
–> alias "Macintosh HD:Library:"

set libFol to path to library folder from user domain
–> alias "Macintosh HD:Users:maro:Library:"

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

たいていは、自分のユーザーディレクトリの下にあるフォルダを扱う場合がほとんどなので、user domainを指定することになるでしょう。

02/17 AppleScriptにおける「パス」について(2)

AppleScriptにおけるパス記述方式は、Mac OS形式、POSIX path形式、URL形式の3つがあります。出現頻度および重要性もこの並びのとおりです。

■Mac OS形式

フォルダ名を「:」で区切って記述する、Classic Mac OSから引き継がれたパス記述形式。AppleScriptの世界でもっともよく使われます。「東京都練馬区中村橋」という住所をMac OS形式で記述すれば、

  東京都:練馬区:中村橋:

になります(中村橋がファイルではなくフォルダの場合)。「中村橋」がファイルである場合には、

  東京都:練馬区:中村橋

になります。

ハードディスクの名称が「Macintosh HD」で、ユーザーが「maro」の場合のホームディレクトリは、

  Macintosh HD:Users:maro:

と表現されます。aliasはこの形式で表現されます。

■POSIX path形式

UNIXの世界で用いられるパス記述形式です。ディレクトリ(フォルダ)階層を「/」で区切ります。また、パスの途中にスペースなどが入る場合には、パス全体をクォートでくくる必要があります。

さきほどの東京都練馬区中村橋は、

  /東京都/練馬区/中村橋/

のように表現されます。特筆すべき点は、このPOSIX pathはルート「/」を頂点とするツリー構造であり、HDDの名前が変わろうがその構造は変わりません。

ハードディスクの名称が「Macintosh HD」で、ユーザーが「maro」の場合のホームディレクトリは、

  /Users/maro/

ハードディスクの名称が「Hiyoko」で、ユーザーが「maro」の場合のホームディレクトリも、

  /Users/maro/

という形式で表現されます。AppleScriptの世界におけるパスはMac OS形式で統一されることが望ましいところですが、shellコマンドを呼び出すような場合には必要になりますし、一部の出来の悪いアプリケーションがこのpathを必要とします(CocoaではPOSIX pathが使われるため)。パス処理関連で代表的な出来の悪いアプリケーションとして、Adobe Acrobat DistillerとKeynoteがあります。

とくに、Adobe Acrobat Distillerでは、POSIX形式のパスにクォート処理を行って渡すとエラーになるなど、本当にチェックしてから発売しているのか疑問に思えるほどです。

path1.jpg

Keynoteでは、ファイルのオープンにaliasを要求するのに、画像を連続配置するmake image slidesコマンドではPOSIX pathを要求します。

path2.jpg

path3.jpg

こうした、出来の悪いアプリケーションが存在することを意識したうえで、Mac OS形式とPOSIX path形式を使い分ける必要があります。また、これらの形式は相互変換できるように命令が用意されています。

■URL形式

ほとんど登場する機会はないのですが、Webブラウザなどにファイルを指定するような場合に使います。基本的にはPOSIX pathと同じですが、先頭にプロトコルを示す「file://」が付くことと、マシンのローカルに存在していることを示すために、localhostからパスが始まります。

ハードディスクの名称が「Macintosh HD」で、ユーザーが「maro」の場合のホームディレクトリは、

  file://localhost/Users/maro/

という形式で表現されます。URL形式では空白文字や一部の特殊記号、日本語の文字列などはURLエンコードされるため、パスの途中に空白文字を含むフォルダが存在する場合でも、クォート処理を行う必要はありません。

set a to choose folder

tell application “Finder”
  set aInfo to URL of a
end tell

–> “file://localhost/Users/maro/“

なお、AppleScriptの標準命令ではURL形式からMac OS形式に戻すことができません。本Blog上に掲載している「URLエンコードされたファイルパスを元のテキスト(POSIX Path)に戻す」サブルーチンを用いてPOSIX pathに変換し、そこからaliasに変換することはできます。

02/16 AppleScriptで扱う「パス」について(1)

AppleScriptにかぎらず、HDD内のどこかに入っているファイルとか、自分のホームフォルダの「書類」フォルダとか、意図したものを指し示して処理を行いたいという場合がものすごく多くあります。

一般的に、そういうファイルシステム中における階層的な位置情報を「パス」と呼びます。英語でいうとpathです。

path.jpg

パスは住所の表記によく似ています。ただ、人に伝える住所はちょっと間違いがあってもなんとかなりますが、プログラム中に記述するパスには一切間違いが許されません。

「東京都練馬区中村橋」という住所があったとして、人に伝える場合には「とうきょうと 練馬く中村橋」でも伝わりますが、プログラム中ではこれが1文字間違っただけでも別の住所と見なされることになります。たとえ、空白文字(スペース)が抜けたとか、そうしたささいな間違いも許容されません(1バイトのアルファベットの大文字小文字の違いは同一視されます。これは、Mac OS Xが標準採用しているHFS plusの仕様です)。

そんなわけで、プログラム中にパスを書いておくのは、けっこう骨が折れる作業です。

さらに、プログラムを他人のマシン上でも動作させることを考えると、HDDの名称やユーザー名も違う可能性が高いので、ユーザーの環境情報を取得しつつ、パスを組み立てるという作業が必要になります。このあたり、昔のClassic Mac OSでは必要のなかった話ですが、Mac OS Xになって少々複雑に(ちょっとだけですが)なった話です。

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上で選択中のフォルダの中に入っているものの中から、フォルダだけ残してファイルを消去する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

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

11/25 擬似的にPropertyファイルを使ってカウントアップ

保存ファイルを~/Library/Preferencesに作成し、カウントアップを行います。

カウンター値を保持する場合には、propertyでScript中に保持しておくのが一番簡単ですが、AppleScriptのプログラムを書き換えてしまうと初期値に戻ってしまいます。そこで、初期設定ファイル(もどき)を作成して、リストの値をそのまま保存。こうしておけば、プログラムを書き換えて実行しても、カウント内容が維持されます。

本物のplistファイルで値を保持してもいいのですが、より簡単かつ安直にファイルに書き込んで使ってもよいだろう、というアプローチです。

スクリプト名:Propertyファイルを使ってカウントアップ
set aRes to countUp(“jp.piyomarusoft.counter.pref”) of countUpKit

script countUpKit
  –カウントアップ
  
on countUp(anIDentifier)
    set apDir to (path to preferences folder from user domain) as string
    
set a to apDir & anIDentifier
    
tell application “Finder”
      set fRes to exists of file a
      
if fRes = false then
        –初期設定ファイルがなければ初期化(1からカウントアップし直し)
        
write_to_file_AsList({1}, a) of me
        
return 1
      else
        set aCount to read file a as list
        
set aaCount to (item 1 of aCount as number) + 1
        
write_to_file_AsList(aaCount, a) of me
        
return aaCount
      end if
    end tell
  end countUp
  
  
–ファイルの追記ルーチン「write_to_file_AsList」  (リストとして書き込み)
  
–データ、対象ファイル
  
on write_to_file_AsList(this_data, target_file)
    try
      set the target_file to the target_file as text
      
set the open_target_file to open for access file target_file with write permission
      
set eof of the open_target_file to 0
      
write this_data to the open_target_file starting at eof as list
      
close access the open_target_file
      
return true
    on error error_message
      try
        close access file target_file
      end try
      
return error_message
    end try
  end write_to_file_AsList
end script

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

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の実力がぜんぜん発揮されない)ファイル処理がちょっとだけ楽しくなったら、素敵なことではないでしょうか。

07/22 ファイル名文字列から拡張子のみ取得する

ファイル名文字列から拡張子のみ取得するAppleScriptです。

URLからファイル名部分を求めたのちに、ファイル名の文字列から拡張子部分だけを取り出すために作成しました。

もっと具体的にいえば、URL Access Scriptingで指定URLのファイルをダウンロードする時に、URLからファイル名を求め……32文字を超えるようであれば、ファイル名を縮めるために、あらかじめ拡張子を求めておいて、ファイル名を短くしたあとに拡張子を付加する……という処理のために作成しました。

割と、どうということはない処理内容ですが、同じ処理を2度書くのはかったるいのでサブルーチンにしておいた次第です。

スクリプト名:ファイル名文字列から拡張子のみ取得する
set fileNameStr to aslakjlasdjlasaaaaaaaaaaaaaaa.jlasldas_das_001.jpg
set aRes to retExtNameFromFilenameStr(fileNameStr) of me

ファイル名文字列から拡張子のみ取得する
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

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

06/20 ファイルの安全な書き出し

本Blogで使用している「AppleScriptのHTML書き出しツール」(AppleScriptで書いてあります)を使っていて、Mac OS X 10.5環境でうまくファイルを書き出せないケースに遭遇したことがありました。

一度テンポラリ領域(path to temporary items from system domain)に書き出したあとにiconvでutf-8にコード変換しているのですが、ファイルの書き出しを行おうとしてエラーで止まる。何回かそんなケースに遭遇するうちに、安全なファイル書き出しを試作すべきでは? と考え……一度テンポラリ領域に安全な名前で書いてから、あとでファイルを移動しつつリネームするという処理を書いてみました。

先のHTML書き出しツールでいえば、テンポラリ領域への書き出し時にこのルーチンを使用し、一度安全な名前で書き出してからリネームされるようになります。はたして、どこに問題があるのか見えてきていませんが、これで様子を見たいところです。

スクリプト名:ファイルの安全な書き出し
set aFPath to choose file name
set aData to ABC
set fRes to write_to_file_Safely(aData, aFPath) of me

安全なファイルの書き出し
on write_to_file_Safely(this_data, target_file)
  set finalPath to target_file
  
  
テンポラリフォルダに一度書き出して、ターゲットのパスに移動  
  
set tmpFol to path to temporary items from system domain
  
set tmpName to do shell script date +%Y%m%d%H%M%S
  
set tmpPath to (tmpFol as string) & tmpName
  
  
テンポラリのパスにファイル書き出し
  
try
    set the target_file to the tmpPath as text
    
set the open_target_file to open for access file target_file with write permission
    
set eof of the open_target_file to 0 つねにoverwrite mode
    
write this_data to the open_target_file starting at eof
    
close access the open_target_file
    
  on error error_message
    try
      close access file target_file
    end try
    
return error_message
  end try
  
  
ファイルの移動を行う
  
set tFilePOSIX to quoted form of POSIX path of target_file
  
set fPathPOSIX to quoted form of POSIX path of finalPath
  
set sText to mv & tFilePOSIX & & fPathPOSIX
  
try
    do shell script sText
  on error error_message
    return error_message
  end try
  
  
return true
  
end write_to_file_Safely

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