1

I have made a folder action AppleScript which mainly gets the folder name with path of the attached folder and calls a ruby script with the pathname as the argument. This works perfectly but is there a way to embed this ruby file inside the AppleScript as a variable, so I don’t have to deal with two files?

I am new to this so if an example is provided would be great. Thanks.

I am trying the code given below but getting an error "-e:82: syntax error, unexpected end-of-input, expecting keyword_end" number 1.

As instructed I have copied the file and inserted the escape \ character, not changed any code. the third commented line will run the program without any error.

set folder_name to quoted form of "/Volumes/HackSSD/Testing Space"

display dialog folder_name

--set makeDateFolders to "/Users/raj/Documents/ivfolders.rb " & folder_name

set rubyScript to "# ivfolder.rb
require 'set'
require 'benchmark'
require 'date'
require 'fileutils'
require 'open3'

raise ArgumentError, 'Expecting single command-line value' if ARGV.length > 1

def file_created_date(ivfile)
  # Not all images have a uniform EXIF/IPTC tag name for created date/time.
  # Use exiftool if installed and attempt three different date tags. If these
  # find no creation date, return the System creation date.
  # returns created_date as 'yyyy-mm-dd' string

  exiftool = '/usr/local/bin/exiftool'
  create_date = ''

  if File.exist?(exiftool)
    create_date, = Open3.capture2(exiftool, '-s3', '-d', '%F',
                                  '-DateTimeOriginal',
                                  '-FileModifyDate',
                                  '-CreateDate',
                                  ivfile)[0]

    if create_date && create_date.count(\"\\n\") > 1
      # n-tuple dates found, usually the same, but take oldest if present.
      datestr = create_date.split(\"\\n\").min
    elsif create_date
      # one date, likely the FileModifyDate. Remove trailing newline
      datestr = create_date.chomp
    end
    return datestr unless create_date.empty?
  end
  File.birthtime(ivfile).strftime('%F') if create_date.empty?
end

# check folder name to see if it is in YYYY-MM-DD format
def valid_date?(str, format = '%F')
  Date.strptime(str, format)
rescue ArgumentError
  false
end


# file excluded if not in this set.
extensions = Set.new(['.cr2', '.cr3', '.nef', 'dng', '.arw', '.gif', '.jpg',
                      '.jpeg', '.jp2', '.png', '.ai', '.psd', '.svg', '.tif',
                      '.tiff', '.heic', '.heif', '.mp4', '.hevc', '.mov',
                      '.m4v', '.avi', '.mts', '.mpg'])

folders = Set.new
matched_files = Set.new
filecnt = 0
foldercnt = 0

elapsed = Benchmark.realtime do
  start_folder = File.expand_path(ARGV.first)

  Dir.chdir(start_folder) do
    Dir.glob(\"#{start_folder}/*.*\").select do |f|
      matched_files << f if extensions.include?(File.extname(f.downcase))
    end

    # if previous run, collect existing folders matching yyyy-mm-dd
    Dir.glob(\"#{start_folder}/*\").select do |f|
      z = File.basename(f)
      folders << z if valid_date?(z) && z.length == 10
    end

    matched_files.each do |f|
      # create_date = File.birthtime(f).strftime('%F') # yyyy-mm-dd
      create_date = file_created_date(f)
      FileUtils.mkdir(create_date, mode: 0o0755, verbose: false) 
                unless folders.include?(create_date)
      folders << create_date
      FileUtils.mv(File.basename(f), create_date, verbose: false)
    end
    filecnt = matched_files.count
    foldercnt = folders.count
  end
end"

do shell script ("ruby -e " & (quoted form of rubyScript) & space & folder_name) -- run it

In my folder action script which is working fine I am taking care of when the folder action is triggered after a folder is created, the actual working script is given below. As mentioned earlier I want to embed the ruby script to not bother with an external file. The Working Folder Action Script

on adding folder items to this_folder after receiving added_items
    try


        repeat with theCurrent_item in added_items
            set filePosixPath to quoted form of (POSIX path of (theCurrent_item as alias))
            set fileType to (do shell script "file -b " & filePosixPath) --Test if it is a directory
            if fileType = "directory" then
                return
            end if

        end repeat


        set folder_name to quoted form of (POSIX path of (this_folder as alias))

        set makeDateFolders to "/Users/raj/Documents/ivfolders.rb " & folder_name


        do shell script makeDateFolders

    end try
end adding folder items to
  • The script has a misplaced 'unless` statement where you are moving multiple files, and errors when trying to create folders that already exist, but after fixing those it works for me as far as I can tell. – red_menace Oct 1 at 3:38
  • How to solve the syntax error I am getting and your modified code please – Raj Khandwala Oct 1 at 10:20
  • Adding an item to an attached folder will trigger the folder action again - what are you using for the destination folder, and how were you using the folder action before? – red_menace Oct 1 at 17:10
  • Have you considered watching the folder using a Ruby native approach, such as stackoverflow.com/questions/4747344/… ? This would avoid mixing in AppleScript. – Graham Miln Oct 2 at 17:50
2

A Ruby script can be placed into an AppleScript string for use with do shell script, but note that special characters in the string such as backslash and double quotes will need to be escaped with a backslash. There are a couple of different arrangements you can use, my preference is a here document, for example:

on run -- Script Editor or application double-clicked
    doStuff for (choose file with multiple selections allowed)
end run

on open theFiles -- items dropped onto the application
    doStuff for theFiles
end open

on adding folder items to this_folder after receiving these_items -- folder action
    doStuff for these_items
end adding folder items to

to doStuff for someFiles
    set argString to "" -- create an argument string from the item list
    repeat with anItem in someFiles -- quote and separate
        set anItem to POSIX path of anItem
        set argString to argString & quoted form of anItem & space
    end repeat

    set heredoc to "<<-SCRIPT
# place your (escaped for AppleScript strings) code here, for example:
ARGV.each_with_index do |arg, index|
  puts \"Argument #{index}:  #{arg}\"
end
SCRIPT"

    set scriptResult to (do shell script "/usr/bin/env ruby - " & argString & heredoc) -- run it
    return paragraphs of scriptResult -- or whatever
end doStuff

The -e option can also be used instead of the here document (see the Ruby man page), for example:

    set rubyScript to "# place your (escaped for AppleScript strings) code here, for example:
ARGV.each_with_index do |arg, index|
  puts \"Argument #{index}:  #{arg}\"
end"

    set scriptResult to (do shell script "/usr/bin/env ruby -e " & (quoted form of rubyScript) & space & argString) -- run it
  • This information is what I was looking for let me absorb it, try it and in a day or two will give my result of success or problems encountered. – Raj Khandwala Sep 30 at 17:31
0

do shell script

You should use the AppleScript command do shell script. This command can run an external command or run a quoted script.

Apple provide this example for perl embedded in AppleScript:

set mySlug to do shell script ¬
    "perl -e 'my (undef, undef, undef, $d, $m, $y) = localtime;
              my $date = sprintf("%4d-%02d-%02d", $y+1900, $m+1, $d);
              print $date'"

See also How to run a shell script from an AppleScript?

  • I understand the use for calling a script, but I want to open the ruby file selecting all the code lines, copying it, then opening my AppleScript pasting the code. I want the syntax for assigning this block of ruby code to a string variable say X and executing it by do shell Script X my existing code is set folder_name to quoted form of (POSIX path of (this_folder as alias)) set makeDateFolders to "/Users/raj/Documents/ivfolders.rb " & folder_name do shell script makeDateFolders – Raj Khandwala Sep 29 at 11:17
  • I have added Apple's example of an inline perl script. I presume ruby has an equivalent to the -e command line flag. If this does not work for you, then please edit your question to add your attempted approaches. – Graham Miln Sep 29 at 12:11
0

During the past week I was searching the web for my solution and I found ExifTool. its a program which allows one to examine and write metadata of various file types. I solved the program 2 ways

  1. Applescript
on adding folder items to this_folder after receiving added_items
    try

        repeat with theCurrent_item in added_items
            set filePosixPath to quoted form of (POSIX path of (theCurrent_item as alias))
            set fileType to (do shell script "file -b " & filePosixPath) --Test if it is a directory
            if fileType = "directory" then
                return
            end if

        end repeat


        set folder_name to quoted form of (POSIX path of (this_folder as alias))

        set ExifTool to "/usr/local/bin/exiftool  '-directory<CreateDate'  -d %Y-%m-%d "
        do shell script "cd " & folder_name & "; " & ExifTool & folder_name

    end try
end adding folder items to
  1. Shell Script in Automator created a new workflow for folder action and dragged the action to run shell script (/bin/bash) to right and put the following code
f=$(dirname "${1}") #Get directory path will put a code to see that it is a file and not a folder
cd "$f"

/usr/local/bin/exiftool '-Directory<CreateDate' -d %Y-%m-%d $f

Both works By the way when you put any type of media file in the attached folder it will create a directory YYYY-MM-DD if not present and move the file based on the Exif CreateDate tag, which is the time the picture or video was shot.

Thanks to all for your valuable inputs.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .