#!/usr/bin/perl # runScriptFromClipboard: # This script runs the script (shell script or AppleScript) # that is currently in the Clipboard. # (i.e. the script text that had previously been copied to the Clipboard) # Any command-line arguments will be sent to the script. # # Cameron Hayne (macdev@hayne.net) Oct 2006 use strict; use warnings; # runAppleScript: Runs the supplied AppleScript # The arguments to this function are: # - the text of the AppleScript # - the command-line args to be passed to the AppleScript sub runAppleScript($$) { my ($ascript, $args) = @_; my $result = `/usr/bin/osascript - $args<<" EOT" $ascript EOT `; chomp($result); return $result; } # getTextFromClipboard: Gets the contents of the clipboard sub getTextFromClipboard() { my $text = `pbpaste`; return $text; } # writeStringToTempFile: saves the given string to a temp file # and returns the name of that file sub writeStringToTempFile($) { my ($str) = @_; use IO::File; use POSIX qw(tmpnam); # the following is from the Perl Cookbook my $filename; my $fh; # try new temporary filenames until we get one that didn't already exist do { $filename = tmpnam() } until $fh = IO::File->new($filename, O_RDWR|O_CREAT|O_EXCL); print $fh $str; $fh->close(); return $filename; } # saveScriptToFile: Saves the given text to a temp file, # makes that file executable, # and returns its name sub saveScriptToFile($) { my ($script) = @_; my $scriptFile = writeStringToTempFile($script); chmod 0700, $scriptFile or die "Can't make script executable: $!\n"; return $scriptFile; } sub escapeDoubleQuotes($) { my ($str) = @_; # we need to escape both backslashes and double-quotes # e.g.: " -> \" \ -> \\ \" -> \\\" $str =~ s/([\\"])/\\$1/g; return $str; } # confirmScript: Asks the user to confirm that he/she wants to run this script. # Returns 1 if confirmed, 0 otherwise sub confirmScript($$$) { my ($scriptType, $script, $scriptArgs) = @_; my $message = "Please confirm that you want to run this "; $message .= "$scriptType " unless $scriptType eq "unknown"; $message .= "with the arguments: $scriptArgs" if $scriptArgs; my $timeout = "120"; # seconds my $ascript =<<" EOT"; tell application "TextEdit" make new document at end of documents set text of document 1 to "$script" activate set status to 0 try display dialog "$message" giving up after $timeout if (gave up of result) is false then set status to 1 end if on error -- we get here if user canceled, nothing to do end try close document 1 without saving end tell -- bring Terminal to the front again tell application "Terminal" activate end tell set result to status EOT my $status = runAppleScript($ascript, ""); return $status; } # determineScriptType: tries to determine what type the given script file is sub determineScriptType($) { my ($filename) = @_; my $scriptType = "unknown"; # first try to identify it via the 'file' utility my $outputFromFile = `/usr/bin/file -b $filename`; if ($outputFromFile =~ /(.*) script text executable$/) { $scriptType = $1; } if ($scriptType eq "unknown") { open(FILE, "<$filename") or die "Can't open file \"$filename\": $!\n"; while () { if (/^\s*tell\s+/) { # has a line starting with 'tell' $scriptType = "AppleScript"; last; } if (/^\s*do\s+shell\s+script\s+/) { # has a line starting with 'do shell script' $scriptType = "AppleScript"; last; } } close(FILE); } return $scriptType; } MAIN: { my $scriptArgs = join(" ", @ARGV); my $script = getTextFromClipboard(); die "Error: no script found\n" unless $script; my $scriptFile = saveScriptToFile($script); my $scriptType = determineScriptType($scriptFile); if (confirmScript($scriptType, escapeDoubleQuotes($script), $scriptArgs)) { if ($scriptType eq "AppleScript") { runAppleScript($script, $scriptArgs); } else { # assume it's a shell script system("$scriptFile $scriptArgs"); } } unlink($scriptFile); }