Applescript:如何根据文件名设置 'move to' 文件夹以将文件排序到按字母顺序排列的文件夹中?

Applescript: How do I set a 'move to' folder based on the filename to sort files into Alphabetical folders?

我正在尝试创建一个 'folder action',它将根据文件名的第一个字母为字母表中的每个字母组织添加到子文件夹中的新文件。

我编写了以下代码,用于将添加到子文件夹 "A" 中的所有内容作为起点移动,但现在我遇到了障碍。

on adding folder items to thisfolder after receiving added_items
repeat with i from 1 to number of items in added_items
    set this_item to (item i of added_items)
    set DestinationFolderName to "A"
    tell application "Finder"
        move this_item to folder DestinationFolderName of thisfolder with replacing
    end tell
end repeat
end adding folder items to

我现在的难题是如何更改 set DestinationFolderName to "A" 以响应 this_item 的文件名。

我尝试了 set DestinationFolderName to text 1 thru 1 of filename 和其他一些迭代,但问题似乎是找到文件名以提取第一个字母。

如有任何帮助,我们将不胜感激。

首先,不鼓励将文件移动到文件夹操作文件夹的子文件夹中,因为此时您正在创建子文件夹,文件夹操作会再次触发,这可能会导致无限循环。

要将文件移动到可能创建的文件夹 on-the-fly shell 命令 ditto 是首选解决方案,因为它能够隐式创建中间目录。

此代码使用桌面上的文件夹 Test 作为目标位置(尾部斜杠很重要)并在 AppleScriptObjC 的帮助下使用处理程序来获取文件名的大写首字母.

由于 ditto 复制文件,需要额外的 rm 行来删除源文件

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

use framework "Foundation"

on adding folder items to thisfolder after receiving added_items
    set destinationFolder to POSIX path of (path to desktop) & "Test/"
    repeat with i from 1 to number of items in added_items
        set this_item to item i of added_items
        tell application "System Events" to set fileName to name of this_item
        set prefix to uppercasedFirstCharacter(fileName)
        set destinationFile to destinationFolder & prefix & "/" & fileName
        do shell script "ditto " & quoted form of POSIX path of this_item & space & quoted form of destinationFile
        do shell script "rm " & quoted form of POSIX path of this_item
    end repeat
end adding folder items to


on uppercasedFirstCharacter(theString)
    set cocoaString to current application's NSString's stringWithString:theString
    return (cocoaString's substringToIndex:1)'s uppercaseString() as text
end uppercasedFirstCharacter

如@vadian 提供的答案中所述,将文件移动到 sub-folders 个带有附加文件夹操作命令的文件夹中绝不是一个好主意。

出于此脚本的目的,我在桌面上创建了一个名为“New Destination”的新(移动到)文件夹,其中将包含子文件夹“A”、“B”、“C”等...

如果正在移动的文件,例如以字母“D”开头,并且没有相应的移动到名为“D”的目标文件夹,在名为“New Destination”的文件夹中,则文件夹“D”将是自动创建

SATIMAGE Scripting Addition在本脚本中使用,如果被移动的文件名的首字母为小写,对应的可能创建的文件夹将由小写变为大写

property DestinationFolderName : missing value
property moveToFolder : (path to desktop folder as text) & "New Destination"

on adding folder items to this_folder after receiving these_items
    repeat with i from 1 to number of items in these_items
        set this_item to item i of these_items
        tell application "Finder"
            set fileName to name of item this_item
            set DestinationFolderName to character 1 of fileName
        end tell

        -- SATIMAGE scripting addition is needed for next command
        set DestinationFolderName to uppercase DestinationFolderName

        tell application "Finder"
            set checkExists to moveToFolder & ":" & DestinationFolderName
            try
                if not (exists of checkExists) then
                    make new folder at moveToFolder ¬
                        with properties {name:DestinationFolderName}
                end if
            end try
            move this_item to folder DestinationFolderName of folder moveToFolder with replacing
        end tell
    end repeat
end adding folder items to

我看到你已经在这方面得到了帮助,但我想提供另一种替代解决方案,它不使用外部框架或 third-party 工具(并不是说使用这些有什么问题,当然)。

我还想评论使用监视文件夹作为根目录的问题,您可以在其中进一步创建 sub-folders,我将在展示我的脚本后这样做:

    property alphabet : "ABCDEFGHIJKLMNOPQRSTUVWXYZ:abcdefghijklmnopqrstuvwxyz"


    on adding folder items to thisfolder after receiving added_items
        
        tell application "Finder" to ¬
            repeat with this_item in the added_items
                get this_item's name
                get the first character of the result
                my capitalise(the result)

                set DestinationFolderName to the result
                
                if not (exists folder DestinationFolderName in folder thisfolder) then ¬
                    make new folder in folder thisfolder with properties ¬
                        {name:DestinationFolderName}
                
                move this_item to folder DestinationFolderName of folder thisfolder
            end repeat
        
    end adding folder items to


    to capitalise(l as text)
        local l
        
        considering case
            set x to (the offset of l in the alphabet) mod 27
        end considering
        
        return character x of the alphabet
    end capitalise

您会注意到此脚本包含一个我编写的名为 capitalise() 的 sub-routine(处理程序)。这需要一个字母和 returns 它的大写形式,基本上只使用一行代码。

检索到添加项的名称,首字母大写。如果使用该字母命名的 sub-folder 尚不存在,则会创建一个,然后将添加的项目移入其中。

它与您的脚本基本相同,只是增加了使用文件名的第一个字母创建文件夹的功能on-the-fly。


无限回归...

关于在监视文件夹中创建 sub-folders 导致无限循环的恐惧,@vadian 强调此问题是绝对正确的,因为它可能会以他描述的方式出现。在编写涉及更改正在监视的文件夹的脚本时,需要注意这一点,通常,最简单的做法就是避免这样做。

但是,也许在某些情况下您想要需要将文件存储在正在观看的文件夹中。如果您从未被允许这样做,那么被监视的文件夹就不会真正起到文件夹的作用;它只是充当 droplet(一个脚本,您可以将文件和文件夹拖放到该脚本上以执行某些操作)。

因此,虽然您绝对应该 小心 以这种方式使用监视文件夹,但您可以通过适当的保护措施来相当合理地这样做,以防止无限倒退。举个简单的例子,假设您的脚本只需要对 filesnot folders 进行排序;简单的解决方案是让脚本忽略它收到的任何文件夹。

但是,实际上,我们在这里甚至不需要这样做:我们可以让它平等地处理文件和文件夹,并且不会发生任何不良情况。

这是创建 sub-folder 然后将项目移入其中的脚本部分:

    if not (exists folder DestinationFolderName in folder thisfolder) then ¬
        make new folder in folder thisfolder with properties ¬
                    {name:DestinationFolderName}

    move this_item to folder DestinationFolderName of folder thisfolder

请注意,sub-folders 始终在同一个位置创建:thisfolder,即正在观看的文件夹;它不是要创建嵌套文件夹。也不是那样,如果已经存在一个使用正在处理的字母命名的文件夹,那么它不会尝试创建另一个文件夹。最后一个潜在的担忧可能来自于尝试然后 move a sub-folder 进入自身。嗯,这不能在 Finder 中完成。 不可能。所以,脚本会默默地抛出错误,然后终止,这正是我们想要的。

总结

我不是强迫您选择一种方法而不是另一种方法,也不是无视 @vadian.

等熟练程序员的重要建议

可以,但是,使用您监视的文件夹将排序的文件非常安全地存储在他们的 sub-folders 中,已提供你要注意如何编写这些东西。