Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

VideoBeagle

macrumors 6502a
Original poster
Aug 17, 2010
823
18
App Q&A testing by request.
I have a couple of perl scripts. I would like to use Applescript to give them some UI features (one applescipt for each different perl script).

they run from the command line, thus:
Code:
>:perl script.pl argument1 argument2.....argumentN
the results of the script go into the folder you've navigated to in Terminal (so running it from a folder ~/Test/ puts the results in /Test/).

I should be able to run them from an applescript, either by running a shell script or controlling terminal.

WHAT I'D LIKE TO DO is instead of having the perl script reside as a file somewhere on my mac, I'd like for it to be embedded in the applescript itself. (so it's portable, can be easily moved to different machines, distributed, etc).

I'm only at the beginning of my research on this idea but so far I'm finding mixed answers to whether this is possible from age old posts that aren't exactly what I'm asking.

So, IS what I want to do possible to do?


If the kind of perl script matters to the question, this is a simple sample of the kinds of scripts I'm using. If I can get this to work, the others will work.
Code:
#!/usr/bin/perl -w
use strict;
use warnings;
use POSIX;
use Data::Dumper;

# Log activity to a file.
sub Logger {
  my $file = shift;
  my $msg = shift;
  my $stop = shift || 0;
   
  open(my $LOG, ">>", $file) || die "Could not create log file.\n" . $!;
  #print $LOG sprintf("%s: %s\n", strftime("%H-%M-%S", localtime), $msg);  -Time Stamp in log files
  print $LOG sprintf("%s\n", $msg);
  close($LOG);
   
  # Exit with error
  unless ($stop == 0) { exit 1; }
}

# Globals
my $logfile = strftime("%Y%m%d%H%M%S", localtime) . "_md.log";
my $count = 1;

# Loop through the given numbers
OUTER: foreach my $number (@ARGV) {
   
  # Create a directory. Make sure it exists. Log an exit if you cannot.
  unless (-d $number) {
  mkdir($number);
  unless (-d $number) {
  Logger($logfile, sprintf("%s. Could not make directory",$count,$number));
  }
  }
   
  $count++;
}

# Log the end of the program
# Logger($logfile, "Stopping");

# exit without error
exit 0;
 
I have to confess that I know nothing about perl scripting, but what you describe should be possable with AppleScript, or AppleScriptObjC, using the "do shell script" command, or using the NSTask class in the OSX Cocoa Framework.
To embbed your perl scripts into an AppleScript, you would have to create the AppleScript as a Cocoa AppleScript App, which can be done in Script Editor from the File > New from Template menu item, this will give you an App bundle which can contain various resources like your perl scripts, although you would be limited to the various basic AppleScript dialog type boxes for your UI elements.
Alternativly you could create a Cocoa AppleScript project in Xcode, which would be my preference, as this would allow you to create a full featured custom interface, which would only be limited by your imagination.

It would be helpful to know which version of OS X you are using, and also intending to run the App on, as AppleScript has undergone a lot of changes since 10.6 Snow Leopard, this includes various changes to the syntax, and also it's overall capabilities with the Cocoa Frameworks.
So AppleScripts written in an earlier version of OS X are not guaranteed to run on later versions.

Regards Mark
 
To bundle it all into a self-contained unit, I'd probably restructure it as an Automator Application. This will let you string together sequences of shell commands, AppleScript, GUI, etc. as separate Actions. The output of one will feed into the input of the next one.

Perl will read stdin for its script if no command-file is present. You can make multiline input using repeated -e "one line cmd", but it will be much simpler to use the shell's ability to feed multiple lines to stdin. In has, it's called a "here document", and you can find that heading on the bash man page:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/bash.1.html


As to this question:
... the results of the script go into the folder you've navigated to in Terminal (so running it from a folder ~/Test/ puts the results in /Test/).
the trick to that in Automator is to use the 'cd' command to position a Run Shell Script in the proper directory before executing other commands. For example, if you'd normally do this in a Terminal window:
Code:
perl something goes here
and the input and output is intended to use the current working directory, then you'd put this in the Run Shell Script action:
Code:
cd ~/your/dir/goes/here
perl something goes here
In other words, provide the complete context (move to working directory, run command) in the shell commands.
 
It would be helpful to know which version of OS X you are using, and also intending to run the App on, as AppleScript has undergone a lot of changes since 10.6 Snow Leopard, this includes various changes to the syntax, and also it's overall capabilities with the Cocoa Frameworks.

Sorry..I forgot it's not in my sig :oops:. 10.9.5

To bundle it all into a self-contained unit, I'd probably restructure it as an Automator Application. This will let you string together sequences of shell commands, AppleScript, GUI, etc. as separate Actions. The output of one will feed into the input of the next one.

Perl will read stdin for its script if no command-file is present. You can make multiline input using repeated -e "one line cmd", but it will be much simpler to use the shell's ability to feed multiple lines to stdin. In has, it's called a "here document", and you can find that heading on the bash man page:
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/bash.1.html

Well, the plan is/how i invisioned it was to read in list of text, and then format the command: perl script.pl list1 list2....listn
but the location of the script would be in the script itself, rather than the hardrive.

The way I was envisionion it was more or less like the perl script would be a subroutine that's called.
Automater would allow me to add in an Automater workflow that's used for post processing.


As to this question:

the trick to that in Automator is to use the 'cd' command to position a Run Shell Script in the proper directory before executing other commands. For example, if you'd normally do this in a Terminal window:
Code:
perl something goes here
and the input and output is intended to use the current working directory, then you'd put this in the Run Shell Script action:
Code:
cd ~/your/dir/goes/here
perl something goes here
In other words, provide the complete context (move to working directory, run command) in the shell commands.

So if the Automator or applescript has a "choose target folder" then you'd pass that location into the cd command?
 
So if the Automator or applescript has a "choose target folder" then you'd pass that location into the cd command?
If the target folder and the folder of inputs is the same, then that's how you'd do it. If they're different, then you might do it differently. You'd have to give details on exactly how your perl script works.


I'm going to make a general suggestion here:
Try something and see what happens.​

That is, run some simple tests, and observe how things work. Doing simple tests to gain understanding is a very good way to learn things. Even if you don't get the result you expected, you've tried something concrete, and you can post what you tried and what happened. Worst case, you'll have learned what doesn't work.

If you run into specific problems with what you've tried, post a question here, and tell us exactly what you tried (copy and paste commands), and what the exact output was (copy and paste error messages, etc.). Details are important.


There are plenty of simple shell commands you can run as tests to see how 'cd' works. The simplest is probably 'pwd'. One step above that is 'pwd' with output redirection, e.g.:
Code:
pwd >~/my-test.txt

There are also lots of simple commands that will operate on files in the current directory. For example, the 'file' command. Run it, pass it an argument, redirect output to a log file in ~/, and observe what happens.

After several rounds of "try it and see what happens", you should be able to predict what will happen for a given command. That's a clear indication that you understand what's happening.
 
[I was typing this while chown was typing the above, so it doesn't reflect what's in his comment]

I'll keep some comments on my ongoing work on this for future reference...

I've set up a simple automator workflow that asks for text, then runs the perl script to make a folder in the home folder.

First issue is giving multiple text items (ie. Test1 Test2) produces a folder with name "Test1 Test2" rather than 2 folders named "Test1" and "Test2".

Googling tells me that the argument that gets passed in to a variable $@, so you need to loop thru it to split it up like:
Code:
for f in "$@"
do
echo "$f"
done
Which won't work for Perl, so I'll need to a) figure out how to do it in perl and b) if that'll cause problems for how the real scripts work....
The main problem I see with a loop causing the script to run once many times, rather that running many times at once is it would cause the error log function to make a bunch of one entry logs rather than a single log with a bunch of entries, which while not critical, would be less than desirable.
 
If the target folder and the folder of inputs is the same, then that's how you'd do it. If they're different, then you might do it differently. You'd have to give details on exactly how your perl script works.

The perl script is in my first post under the spoiler button. It works exactly as I described.. it takes in a list of arguments and makes a subfolder for each argument in the folder it's called from.


I'm going to make a general suggestion here:
Try something and see what happens.​

That is, run some simple tests, and observe how things work. Doing simple tests to gain understanding is a very good way to learn things. Even if you don't get the result you expected, you've tried something concrete, and you can post what you tried and what happened. Worst case, you'll have learned what doesn't work.

....

I've done some experiments...I'm right now having to figure out if it's possible to integrate the shell commands like cd with the perl script.

Screenshot%202015-08-08%2016.58.11.png


--------------

I'm thinking that Automator might not work for what i want. It seems to see everything as an individual programs it runs one after another, rather than a sequence of commands.

So I'm back looking at embedding into Applescript itself.
 
Last edited:
Moving back to using perl applescript, and it's a step forward, a step back.

I have a script, it compiles, but when I run it gives a huge Error report.

Code:
do shell script "perl -e '
  #!/usr/bin/perl -w
use strict;
use warnings;
use POSIX;
use Data::Dumper;

# Log activity to a file.
sub Logger {
  my $file = shift;
  my $msg = shift;
  my $stop = shift || 0;
  
  open(my $LOG, \">>\", $file) || die \"Could not create log file.
\" . $!;
  #print $LOG sprintf(\"%s: %s
\", strftime(\"%H-%M-%S\", localtime), $msg);  -Time Stamp in log files
  print $LOG sprintf(\"%s
\", $msg);
  close($LOG);
  
  # Exit with error
  unless ($stop == 0) { exit 1; }
}

# Globals
my $logfile = strftime(\"%Y%m%d%H%M%S\", localtime) . \"_md.log\";
my $count = 1;

# Loop through the given numbers
OUTER: foreach my $number (@ARGV) {
  
  # Create a directory. Make sure it exists. Log an exit if you cannot.
  unless (-d $number) {
  mkdir($number);
  unless (-d $number) {
  Logger($logfile, sprintf(\"%s. Could not make directory\",$count,$number));
  }
  }
  
  $count++;
}

# Log the end of the program
# Logger($logfile, \"Stopping\");

# exit without error
exit 0;'
tessy
"

And

Code:
error "Operator or semicolon missing before %H at -e line 17.
Ambiguous use of % resolved as operator % at -e line 17.
String found where operator expected at -e line 18, near \"print $LOG sprintf(\"\"
  (Might be a runaway multi-line \"\" string starting on line 17)
   (Missing semicolon on previous line?)
String found where operator expected at -e line 27, near \"my $logfile = strftime(\"\"
  (Might be a runaway multi-line \"\" string starting on line 19)
   (Missing semicolon on previous line?)
Having no space between pattern and following word is deprecated at -e line 27.
Operator or semicolon missing before %H at -e line 27.
Ambiguous use of % resolved as operator % at -e line 27.
Operator or semicolon missing before %M at -e line 27.
Ambiguous use of % resolved as operator % at -e line 27.
Operator or semicolon missing before %S at -e line 27.
Ambiguous use of % resolved as operator % at -e line 27.
String found where operator expected at -e line 27, near \"S\", localtime) . \"\"
Bareword found where operator expected at -e line 27, near \"\", localtime) . \"_md\"
   (Missing operator before _md?)
String found where operator expected at -e line 45, at end of line
   (Missing semicolon on previous line?)
Global symbol \"%M\" requires explicit package name at -e line 17.
Global symbol \"%S\" requires explicit package name at -e line 17.
syntax error at -e line 18, near \"print $LOG sprintf(\"\"
Global symbol \"%s\" requires explicit package name at -e line 18.
Global symbol \"%Y\" requires explicit package name at -e line 27.
Global symbol \"%s\" requires explicit package name at -e line 37.
Can't find string terminator '\"' anywhere before EOF at -e line 45.
sh: line 48: tessy: command not found" number 127
I've been poking at this on and off all day, so I'm putting it aside for now.
 
Sorry for my slow reply.

Sorry..I forgot it's not in my sig 10.9.5

Very little changed with AppleScript from 10.9.5 Mavericks to Yosemite, so if you decided to go the AppleScript route, then forward compatibility should not be a problem.

As stated previously, I'm sorry I can't help with any perl scripting issues, but I will watch your posting, and if you have any AppleScript specific issues, then I will assist if I'm able.

Regards Mark
 
Moving back to using perl applescript, and it's a step forward, a step back.

I have a script, it compiles, but when I run it gives a huge Error report.

Code:
do shell script "perl -e '
  #!/usr/bin/perl -w
use strict;
use warnings;
use POSIX;
use Data::Dumper;

# Log activity to a file.
sub Logger {
  my $file = shift;
  my $msg = shift;
  my $stop = shift || 0;

  open(my $LOG, \">>\", $file) || die \"Could not create log file.
\" . $!;
  #print $LOG sprintf(\"%s: %s
\", strftime(\"%H-%M-%S\", localtime), $msg);  -Time Stamp in log files
  print $LOG sprintf(\"%s
\", $msg);
  close($LOG);

  # Exit with error
  unless ($stop == 0) { exit 1; }
}

# Globals
my $logfile = strftime(\"%Y%m%d%H%M%S\", localtime) . \"_md.log\";
my $count = 1;

# Loop through the given numbers
OUTER: foreach my $number (@ARGV) {

  # Create a directory. Make sure it exists. Log an exit if you cannot.
  unless (-d $number) {
  mkdir($number);
  unless (-d $number) {
  Logger($logfile, sprintf(\"%s. Could not make directory\",$count,$number));
  }
  }

  $count++;
}

# Log the end of the program
# Logger($logfile, \"Stopping\");

# exit without error
exit 0;'
tessy
"

And

Code:
error "Operator or semicolon missing before %H at -e line 17.
Ambiguous use of % resolved as operator % at -e line 17.
String found where operator expected at -e line 18, near \"print $LOG sprintf(\"\"
  (Might be a runaway multi-line \"\" string starting on line 17)
   (Missing semicolon on previous line?)
String found where operator expected at -e line 27, near \"my $logfile = strftime(\"\"
  (Might be a runaway multi-line \"\" string starting on line 19)
   (Missing semicolon on previous line?)
Having no space between pattern and following word is deprecated at -e line 27.
Operator or semicolon missing before %H at -e line 27.
Ambiguous use of % resolved as operator % at -e line 27.
Operator or semicolon missing before %M at -e line 27.
Ambiguous use of % resolved as operator % at -e line 27.
Operator or semicolon missing before %S at -e line 27.
Ambiguous use of % resolved as operator % at -e line 27.
String found where operator expected at -e line 27, near \"S\", localtime) . \"\"
Bareword found where operator expected at -e line 27, near \"\", localtime) . \"_md\"
   (Missing operator before _md?)
String found where operator expected at -e line 45, at end of line
   (Missing semicolon on previous line?)
Global symbol \"%M\" requires explicit package name at -e line 17.
Global symbol \"%S\" requires explicit package name at -e line 17.
syntax error at -e line 18, near \"print $LOG sprintf(\"\"
Global symbol \"%s\" requires explicit package name at -e line 18.
Global symbol \"%Y\" requires explicit package name at -e line 27.
Global symbol \"%s\" requires explicit package name at -e line 37.
Can't find string terminator '\"' anywhere before EOF at -e line 45.
sh: line 48: tessy: command not found" number 127
I've been poking at this on and off all day, so I'm putting it aside for now.
The first error (and several others) are because perl doesn't permit literal newlines in double-quoted strings. You've escaped the double-quotes, but you didn't escape the backslashes in your original posted code. Instead you just used a literal newline. If you want a newline in a double-quoted string, you should use the escape sequence \n.
http://www.perlmonks.org/?node=String Literals in Perl

Some of the other errors may just be a result of a parsing-error cascade from the first error near line 17.


Here's one original line:
Code:
  open(my $LOG, ">>", $file) || die "Could not create log file.\n" . $!;
Here's the corresponding "line" that produces the error:
Code:
  open(my $LOG, \">>\", $file) || die \"Could not create log file.
\" . $!;
Here's what you should have used:
Code:
  open(my $LOG, \">>\", $file) || die \"Could not create log file.\\n\" . $!;

Using an earlier suggestion, I suggest making an extremely simple perl program on which you can test the use of escaped double-quotes and escaped backslashes within an AppleScript string. I recommend a perl program that has two lines and prints two output lines. That is, each perl line should produce one line of output, and each output line should end with a newline. Run that and see if it works. If it doesn't, then post the code here.
 
using the NSTask class in the OSX Cocoa Framework.
To embbed your perl scripts into an AppleScript

I'd totally take the approach Mark FX mentions, myself. Mashing AppleScript and perl together just seems odd to me, although I accept that you may have your reasons. Personally I'd see if I could go one step further and try to replicate the functionality of the perl script in Obj-C.
 
I'd totally take the approach Mark FX mentions, myself. Mashing AppleScript and perl together just seems odd to me, although I accept that you may have your reasons. Personally I'd see if I could go one step further and try to replicate the functionality of the perl script in Obj-C.

Well, the thing is.. I don't know Obj-C, the OSX Cocoa Framework, etc. And I'm not about to learn them for this project.
I'm using Perl because my friend who's helping me with this likes to use Perl (I'd prefer Python which I'm much more familiar with, but gift horse and all that.

I had to take a break for a bit on this to work on other stuff, but I'm gonna get back to it this week.
 
Well, the thing is.. I don't know Obj-C, the OSX Cocoa Framework, etc. And I'm not about to learn them for this project.

Fair enough!

I do think that you're making life unnecessarily hard for yourself by shackling yourself to perl though. If you're determined to take that route then others have detailed the options above.

However, I don't know much perl at all but from the look of it all you're doing is creating some folders based on user input. You don't need perl to do that, and perl seems a slightly strange choice to me given that you're already in AppleScript, from the sound of it.

So why not forget perl and do it all in AppleScript from the start? Here's a very rough example of the sort of thing I mean:

Code:
--get some info from the user
set theFolder to choose folder with prompt "Choose a folder to make your folder in"
set theStringOfNumbers to text returned of (display dialog "Please enter a list of names for the folders. Separate the names with commas" default answer "folder_one,folder_two,folder_three")

--make a name for the log file
set theStartTime to do shell script "date \"+%H-%M-%S\""
set theLogFile to (POSIX path of theFolder) & theStartTime & "_md.log"

--split the comma separated list into an actual list
set AppleScript's text item delimiters to ","
set theFolderNameList to every text item of theStringOfNumbers
set AppleScript's text item delimiters to ""


--go through the list and make the folders
repeat with theFolderName in theFolderNameList
    try
        --nb. mkdir -p makes the folder if it doesn't already exist. If it does exist then it fails silently.
        do shell script "mkdir -p " & quoted form of ((POSIX path of theFolder) & theFolderName)
        writeToLog("SUCCESS: Created file " & "(" & theFolderName & ")", theLogFile)
    on error
        writeToLog("ERROR: Failed to create file " & "(" & theFolderName & ")", theLogFile)
    end try
end repeat



--function to log errors to file
on writeToLog(theText, theLogFile)
    --get the current time
    set theLogEntryTime to do shell script "date \"+%Y%m%d%H%M%S\" "
    do shell script ("echo " & quoted form of (theLogEntryTime & ": " & theText) & " >> " & quoted form of theLogFile)
end writeToLog

...okay, so there's a smattering of shell script in there, but it's mostly native AppleScript. If you want much more of a user interface on it than that given by "display dialog" then odds are you're going to have to venture into Cocoa, one way or another.
 
That's not what the real scripts do...that is a sample that does the parts that interact with the mac.
The full scripts takes a bunch of numbers, uses those numbers to make URL's, and fetch specific information from those pages and puts it in folders for a long simmering catalog project.

The perl works fine to do what's needed. The parts that interface with the Mac are taking the numbers in, and creating the folders. If I can get this snipet to work, then the main scripts will work.

My friend has been moving houses, so I haven't gotten back to this project for now.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.