Getting the file name of files dropped on the script - macos

I made this Applescript script to create symbolic links.
Appart from POSIX path of, how can I get the file name, without the path, of the dropped file?
on open filelist
repeat with i in filelist
do shell script "ln -s " & POSIX path of i & " /Users/me/Desktop/symlink"
end repeat
end open
PS: I know this expects many files to be dropped and tries to create many links with the same name, which gives an error. Actually I copied this example from a website and as I don't know almost anything about Applescript, I don't know how to do this for a single file, help on that would be appreciated too.

I'm not sure what precisely you're trying to do, but I have a guess. Is the idea that you want to take every file dropped on the script and create a symbolic link to each one on the Desktop? So if I drop ~/look/at/me and ~/an/example, you'll have ~/Desktop/me and ~/Desktop/example? If that's what you want, then you're in luck: ln -s <file1> <file2> ... <directory> does exactly that. (Edit: Although you have to watch out for the two-argument case.) Thus, your code could look like this:
-- EDITED: Added the conditional setting of `dest` to prevent errors in the
-- two-arguments-to-ln case (see my comment).
on quoted(f)
return quoted form of POSIX path of f
end quoted
on open filelist
if filelist is {} then return
set dest to missing value
if (count of filelist) is 1 then
tell application "System Events" to set n to the name of item 1 of filelist
set dest to (path to desktop as string) & n
else
set dest to path to desktop
end if
set cmd to "ln -s"
repeat with f in filelist & dest
set cmd to cmd & " " & quoted(f)
end repeat
do shell script cmd
end open
Note the use of quoted form of; it wraps its argument in single quotes so executing in in the shell won't do anything funny.
If you want to get at the name of the file for another reason, you don't need to call out to the Finder; you can use System Events instead:
tell application "System Events" to get name of myAlias
will return the name of the file stored in myAlias.
Edit: If you want to do something to a single file, it's pretty easy. Instead of using repeat to iterate over every file, just perform the same action on the first file, accessed by item 1 of theList. So in this case, you might want something like this:
-- EDITED: Fixed the "linking a directory" case (see my comment).
on quoted(f)
return quoted form of POSIX path of f
end quoted
on open filelist
if filelist is {} then return
set f to item 1 of filelist
tell application "System Events" to set n to the name of f
do shell script "ln -s " & ¬
quoted(f) & " " & quoted((path to desktop as string) & n)
end open
It's pretty much the same, but we grab the first item in filelist and ignore the rest. Additionally, at the end, we display a dialog containing the name of the symlink, so the user knows what just happened.

As an example, you can work with the Finder instead of a shell script to get the name of a single file that is dropped on the script that is saved as an application. If you don't need the display dialog, you can remove it, but you have the file name as a variable to work with:
on open the_files
repeat with i from 1 to the count of the_files
tell application "Finder"
set myFileName to name of (item i of the_files)
end tell
display dialog "The file's name is " & myFileName
end repeat
end open

Related

OSX: How can check whether a file exists in current directory using applescript?

I want to make an automator app which creates an empty file in current directory.
I did some google search and found:
http://hints.macworld.com/article.php?story=20050219134457298 and http://hints.macworld.com/article.php?story=20100509134904820
However, I want to do something more powerful.
If the specified file already exists, I want to show a warning instead of overwriting the original file, which is what one of the above link does. (The other one creates a text file using textEdit. I do not want to create text file. I want an empty file like what linux/unix does)
I already figured out how to do most of the part, but
How can check whether a file exists in current directory using applescript??
How can I concatenate two variable in applescript?
Checking if a file exists (assuming thefullpath is already set as in the referenced question):
tell application "Finder"
if exists POSIX file thefullpath then
--do something here like
display alert "Warning: the file already exists"
end if
end tell
Not sure what you mean by the second part but if you want to concatenate strings stored in var1 and var2 you could simply do
var1 & var2
Something I have been using a lot of late for this sort of thing is the command /bin/test
The test test for the existence of in this case a file
if (do shell script "/bin/test -e " & quoted form of (POSIX path of theFile) & " ; echo $?") is "1" then
-- 1 is false
--do something
end if
The -e option:
-e file True if file exists (regardless of type).
The are tons of other test options shown in the /bin/test man page
The following code, adapted from your second link, is usually right, but it doesn't always work. The current directory is better specified as the directory of the document that is being opened which is most likely from the Finder's front window, but not necessarily. I like to write code that will work no matter what.
on run {input, parameters}
tell application "Finder"
set currentPath to insertion location as text
set x to POSIX path of currentPath
display dialog "currentPath: " & (x as text)
end tell
return x
end run
I wrote a whole "Run AppleScript" action to put things into context:
on run {input, parameters}
# count the number of files
set numFiles to 0
repeat with f in input
# warn the user that folders are not processed in this app
tell application "Finder"
if (kind of f is "Folder") then
display dialog "The item: " & (f as text) & " is a folder. Only files are allowed. Do you want to continue processing files or do you want to cancel?"
else
set numFiles to numFiles + 1
end if
end tell
end repeat
# require that at least one file is being opened
if numFiles < 1 then
display alert "Error: the application Test1.app cannot be run because it requires at least one file as input"
error number -128
end if
# get the current directory from the first file
set theFirstFile to (item 1 of input)
tell application "System Events" to set theFolder to (container of theFirstFile)
# ask the user for a file name
set thefilename to text returned of (display dialog "Create file named:" default answer "filename")
# create the file
tell application "System Events" to set thefullpath to (POSIX path of theFolder) & "/" & thefilename
set theCommand to "touch \"" & thefullpath & "\""
do shell script theCommand
# return the input as the output
return input
end run
The "touch" command is OK. If the file doesn't exist, it is created and if it does exist, only the modification date is changed (which isn't too bad) but it doesn't overwrite the file. If your file is being overwritten, it's not the touch command that is doing it.
I changed the default file name to remove the extension ".txt" This extension may default to being opened by TextEdit.app, but you can change this in the Finder by choosing "Get Info" for a file and changing the "Open With" property. You can change which application opens the file with that extension or you can change them all. For example, all of my ".txt" files are opened with BBEdit.app
Will you vote my answer up?
Another option that doesn't require Finder or System Events is to try to coerce a POSIX file or file object to an alias:
try
POSIX file "/tmp/test" as alias
true
on error
false
end try

Applescript copy files to mounted volume; test for file(s) already exists

I am writing a script to allow students to upload their files to a shared folder on teacher's computer in a computer lab (same network). I have a working script that, when executed, will duplicate all files in the folder UPLOAD on the student machine to the folder SUBMISSIONS on the teacher's machine. However, if a file already exists on the teacher machine, the script hangs.
I need to be able to test for the presence of individual files on the teacher machine and either (a) pop a message that says "this file already exists, rename it and upload again" or (b) append something to the file name to differentiate it...a random number or "copy 1" etc.
Ideally I want it to run as a folder action. When a file is added to the "UPLOAD" folder it will automatically be sent to the teacher. But I don't want files to copy over files of the same name...or for the script to hang.
Any thoughts or alterative approaches would be welcome.
Here's my code:
set home_path to path to home folder as string
set work_folder to alias (home_path & "Desktop:" & "Upload")
try
mount volume "afp://[LOGIN INFO].local/Submissions"
set this_folder to result as alias
tell application "Finder"
tell application "Finder"
duplicate every file of work_folder to this_folder
end tell
eject this_folder
end tell
end try
I think that it would help if your try-block had an on-error block to inform you about any errors.
try
# try stuff here
j # this will compile but will throw a runtime error and you can see the error
on error error_message number error_number
display alert "Error: " & error_message & return & return & (error_number as text)
end try
OK. I tried again to write some code. Here is my version.
It does a couple of things differently than the code posted by the original poster.
It copies the files and folders into a new folder on the server with a time-stamp to cope with the problems of whether some of the files already exist on the server.
I changed the wording of the duplicate statement from duplicating every "file" to duplicating every "item" so that folders are duplicated too.
I put in an on-error block in the try-statement to display any errors.
I activate Finder so that you can see the progress window.
I pop up a dialog at the end if there were no errors.
I had a problem that I had to fix:
On the server, I had to enable write permissions for the client or I got a -5000 error.
I think that the following code should work pretty well. It's almost 100% AppleScript. It only uses one call to the shell and that is to get the current date and format it for the time-stamp for new folders created on the server.
# set the path to the "work_folder" where the files are to be uploaded
set home_path to path to home folder as string
set work_folder to alias (home_path & "Desktop:" & "Upload")
# duplicate the files and folders in work_folder to the server
try
# TODO set the name of your server here
set the_volume to mount volume "afp://32-bit.local/Submissions"
set destination_path to the_volume as text
set folder_name to getTimeStamp()
tell application "Finder"
activate
set new_folder to make new folder at alias destination_path with properties {name:folder_name}
duplicate every item of work_folder to new_folder
eject the_volume
display alert "Successfully uploaded the files and folders"
end tell
on error error_message number error_number
if error_number is not equal to -128 then
display alert "Error: " & error_message & return & return & (error_number as text)
end if
end try
# This function returns the current date and time as a time-stamp of the form yyyy-mm-dd-hh-ss
# This function uses a shell script because it's just a lot easier to do than in AppleScript
on getTimeStamp()
set time_stamp to do shell script "date '+%Y-%m-%d-%H-%M-%S'"
return time_stamp
end getTimeStamp
Here's another idea for debugging. You can put in calls to "display dialog" to be able to know where your script is failing:
display dialog "Entering script"
set home_path to path to home folder as string
display dialog "home_path: " & home_path
set work_folder to alias (home_path & "Desktop:" & "Upload")
display dialog "work_folder: " & work_folder as string
try
mount volume "afp://32-bit.local/Submissions"
set this_folder to result as alias
display dialog "this_folder: " & this_folder as string
tell application "Finder"
display dialog "Inside of the first tell application Finder"
tell application "Finder"
display dialog "About to call duplicate"
duplicate every file of work_folder to this_folder
display dialog "Just returned from calling duplicate"
end tell
display dialog "About to call eject"
eject this_folder
display dialog "Just returned from call to eject"
end tell
on error error_message number error_number
display alert "Error:" & error_message & return & return & (error_number as text)
end try
display dialog "Exiting script"
Another debugging technique is to log output to a text file.
Another debugging technique is to purchase the AppleScript debugger:
http://www.latenightsw.com/sd4/index.html
I believe that this debugger costs $200.00 that's too pricey for me, but I've used other debuggers and debuggers are wonderful tools that let you "peek inside" of your script while it's running to see the value of variables and to trace which lines of code are being executed.
This script will copy each file over to the mounted volume. If a file exists with the same name at the destination it will add a number to the end of the copy file name and try that.
Example:if test.doc exists in the folder already then the script will try and copy it with the name test_1.doc and so on..
The original file is never renamed and the older files are never overwritten.
The script is fully commented to explain what it is doing.
** Update2 **
The copy to destination code is now in it's own handler.
The original files are labeled by the finder label index 6 (green) to indicate successful copied.
This will also stop the same original file from being copied twice by using the index colour as a check. If it is labeled index label 7 it will be ignored.
You could if you want move the successful copied files to another folder out of the way using the script. But I have not done this in this script.
set home_path to path to home folder as string
set work_folder to alias (home_path & "Desktop:" & "Upload")
set counter to ""
global counter
--try
set this_folder to mount volume "afp://myMac/UserName/"
this_folder as text
tell application "Finder" to set theFiles to every file of work_folder as alias list #GET ALL FILES OF LOCAL FOLDER AS ALIASES
tell application "Finder" to set theRemoteFiles to (every file of ((this_folder & "Submissions:" as string) as alias)) #GET ALL FILES OF REMOTE FOLDER -- ONLY NEEDED FOR COUNT CHECK LATER
repeat with i from 1 to number of items in theFiles #PROCESS EACH LOCAL FILE
set this_item to item i of theFiles #GET A LOCAL FILE
tell application "Finder" to set LabelIndex to label index of this_item
if LabelIndex is not 6 then
tell application "Finder" to set this_name to displayed name of this_item #GET ITS DISPLAYED NAME
tell application "Finder" to set this_extension to name extension of this_item #GET ITS EXTENSION NAME i.E "txt"
set realName to (do shell script "echo " & quoted form of this_name & "| awk -F '" & quoted form of this_extension & "' '{print $1}'") #GET ITS NAME WITHOUT EXTENSION NAME
set counter to 1 # SET A NUMBER TO ADD TO THE FILE NAME IF THE FILE NAME EXIST ALREADY IN THE REMOTE FOLDER
my checkName(this_name, realName, this_item, this_extension, theRemoteFiles, this_folder) # CALL TO HANDLER THAT WILL DO THE CHECKING AND COPYING
end if
end repeat
tell application "Finder" to eject this_folder
# THE CALL TO THE HANDLER INCLUDES VARIABLES THAT ARE NOT GLOBAL OR PROPERTIES BUT NEED TO BE PASSED ON TO IT I.E(this_name, realName, this_item, this_extension, theRemoteFiles, this_folder)
on checkName(this_name, realName, this_item, this_extension, theRemoteFiles, this_folder)
# (1) IF THE NUMBER OF theRemoteFiles IS GREATER THAN 0 THEN FILES EXIST IN THE REMOTE FOLDER AND MAY CONTAIN FILES WITH THE SAME NAMES AS THE LOCAL ONES. PROCESS..
# (2) IF THE NUMBER OF theRemoteFiles IS NOT GREATER THAN 0.THEN FILES DO NOT EXIST IN THE REMOTE FOLDER AND THE LOCAL ONES CAN JUST BE COPIED OVER.
if (count of theRemoteFiles) is greater than 0 then # (1)
try
my copyOver(this_item, this_folder, this_name)
on error errMssg #WE USE not overwritten ERROR TO TRIGGER THE RENAME THE DESTINATION FILE NAME TO INCLUDE A NEW NUMBER.
--tell application "Finder" to set label index of this_item to 6
if errMssg contains "not overwritten" then
set this_name to (realName & counter & "." & this_extension)
set counter to counter + 1 #WE SETUP THE FILE NAME NUMBER FOR THE POSSIBLE NEXT RUN
# RUN THE HANDLER AGAIN WITH THE CHANED DETAILS
my checkName(this_name, realName, this_item, this_extension, theRemoteFiles, this_folder)
end if
end try
else # (2)
my copyOver(this_item, this_folder, this_name)
end if
end checkName
on copyOver(this_item, this_folder, this_name)
# THE -n OPTION IN THE SHELL COMMAND TELLS CP NOT TO OVERWRITE EXISTING FILES. AN ERROR OCCURE IF THE FILE EXISTS.
# THE -p OPTION IN THE SHELL COMMAND TELLS CP TO PRESERVE THE FOLLOWING ATTRIBUTES OF EACH SOURCE FILE IN THE COPY:
# modification time, access time, file flags, file mode,
#user ID, and group ID, as allowed by permissions. Access Control
#Lists (ACLs) and Extended Attributes (EAs), including resource
#forks, will also be preserved.
# THE -v OPTION IN THE SHELL COMMAND TELLS CP TO USE VERBOS MODE. WHICH GIVES US A BETTER CLUE OF THE ERROR
set theResult to (do shell script "cp -npv " & quoted form of (POSIX path of this_item) & space & quoted form of (POSIX path of (this_folder & "Submissions:" as string) & this_name))
if theResult contains "->" then
tell application "Finder" to set label index of this_item to 6
else
tell application "Finder" to set label index of this_item to 7
end if
end copyOver

Create new folder from files name and move files

(This is a new edit from a previous question of mine which achieved -3 votes. Hope this new one has a better qualification)
I need to create an Automator service to organize a high amount of files into folders. I work with illustrator and from each .ai file I create 3 more formats: [name.pdf], [name BAJA.jpg] and [name.jpg], thats 4 files in total
My problem is that during the week I repeat this process to more than 90 different .ai files. So 90 files * 4 is 360 independent files all into the some project folder.
I want to grab all 4 related files into one folder, and set the folder name as the same as the .ai file.
Since all the file names are identical (except one), I thought of telling the finder to grab all the files with the same name, copy the name, create a folder and put this files inside, but I have a file name variant [name LOW.jpg] Maybe I can tell the script to strip that work as an exception.
That way I will all 4 the files unified into one folder.
Thank you in advance
Update: This problem was originally posted back in 2013, now I have a solution. People help me assembled this script to fit my needs.
I added this as a service and assigned a keyboard shurtcut on MacOs.
This is the code:
on run {input, parameters} -- create folders from file names and move
set output to {} -- this will be a list of the moved files
repeat with anItem in the input -- step through each item in the input
set {theContainer, theName, theExtension} to (getTheNames from anItem)
try
# check for a suffix and strip it off for the folder name
if theName ends with " BAJA" then
set destination to (makeNewFolder for (text 1 thru -6 of theName) at theContainer)
else
set destination to (makeNewFolder for theName at theContainer)
end if
tell application "Finder"
move anItem to destination
set the end of the output to the result as alias -- success
end tell
on error errorMessage -- duplicate name, permissions, etc
log errorMessage
# handle errors if desired - just skip for now
end try
end repeat
return the output -- pass on the results to following actions
end run
to getTheNames from someItem -- get a container, name, and extension from a file item
tell application "System Events" to tell disk item (someItem as text)
set theContainer to the path of the container
set {theName, theExtension} to {name, name extension}
end tell
if theExtension is not "" then
set theName to text 1 thru -((count theExtension) + 2) of theName -- just the name part
set theExtension to "." & theExtension
end if
return {theContainer, theName, theExtension}
end getTheNames
to makeNewFolder for theChild at theParent -- make a new child folder at the parent location if it doesn't already exist
set theParent to theParent as text
if theParent begins with "/" then set theParent to theParent as POSIX file as text
try
return (theParent & theChild) as alias
on error errorMessage -- no folder
log errorMessage
tell application "Finder" to make new folder at theParent with properties {name:theChild}
return the result as alias
end try
end makeNewFolder
Hope this helps.
It's a pity you get downvoted as I, personally, enjoy answering these sorts of questions, as it helps me practise and improve my own skills.
Thanks for posting your solution. I think it's a great gesture and others will find it useful.
This script is a bit shorter than and uses "System Events" instead of "Finder", so will be quicker for large numbers of files:
set IllustratorOutputFolder to "/Users/CK/Desktop/example"
tell application "System Events" to ¬
set ai_files to every file in folder IllustratorOutputFolder ¬
whose name extension is "ai"
set Output to {}
repeat with ai_file in ai_files
set AppleScript's text item delimiters to "."
get name of ai_file
get text items of result
set basename to reverse of rest of reverse of result as text
tell application "System Events"
get (every file in folder IllustratorOutputFolder ¬
whose name begins with basename)
move result to (make new folder ¬
in folder IllustratorOutputFolder ¬
with properties {name:basename})
end tell
set end of Output to result
end repeat
return Output -- list of lists of moved files
Just an alternative way of doing things. Not that it's better or worse, but just a different solution.
You could also save this as script.sh (in TextEdit in plain text mode) and run it with bash script.sh in Terminal:
cd ~/Target\ Folder/
for f in *.ai *.pdf *.jpg; do
dir=${f%.*}
dir=${dir% LOW}
mkdir -p "$dir"
mv "$f" "$dir"
done

Applescript to check if files exist

I want to check if any of particular files (dictionaries) exist in "/Library/Dictionaries/". Here is my Applescript code lines:
tell application "Finder"
try
set theFolder to ("/Library/Dictionaries/")
set fileNames to {"dict1.dictionary", "dict2.dictionary", "dict3.dictionary", "dict_n.dictionary"}
on error
set fileNames to false
end try
if fileNames is not false then
try
display dialog "You have already got the dictionary."
end try
end if
end tell
Weirdly, the message You have already got the dictionary. is always shown albeit no listed files exist.
My purpose is to check if any of the listed files exits, and if one or more of them exits then the message is to be displayed.
In fact, this script will be run as a Unix bash script via /usr/bin/osascript, so I will be very grateful if you can help with either Apple script or Bash script.
Try
set theFolder to (path to library folder as text) & "Dictionaries:"
set fileNames to {"Apple Dictionary.dictionary", "dict2.dictionary", "dict3.dictionary", "dict_n.dictionary"}
set dict to {}
repeat with aFile in fileNames
tell application "Finder"
if exists file (theFolder & aFile as text) then set end of dict to aFile & return
end tell
end repeat
if dict ≠ {} then display dialog "You have the following dictionaries installed:" & return & dict
Another method is to try to coerce a file object to an alias:
set p to (system attribute "HOME") & "/Desktop/test.txt"
try
POSIX file p as alias
true
on error
false
end try
Note that this results in an error when as alias is evaluated:
"/non-existing/path"
tell application "Finder" to exists POSIX file result as alias
This doesn't result in an error:
POSIX file "/non-existing/path"
tell application "Finder" to exists result

Use Automator/Applescript to crop filenames after certain character?

I have a folder containing about 5000 files with names like:
Invoice 10.1 (2012) (Digital) (4-Attachments).pdf
Carbon Copy - Invoice No 02 (2010) (2 Copies) (Filed).pdf
01.Reciept #04 (Scanned-Copy).doc
I want to rename these files by removing everything from the first bracket onwards, so they look like this:
Invoice 10.1.pdf
Carbon Copy - Invoice No 02.pdf
01.Reciept #04.doc
I have found lots of scripts that will remove the last x letters, but nothing that will crop from a particular character.
Ideally I would like to use Automator, but I'm guess this might too complex for it. Any ideas?
Try:
set xxx to (choose folder)
tell application "Finder"
set yyy to every paragraph of (do shell script "ls " & POSIX path of xxx)
repeat with i from 1 to count of yyy
set theName to item i of yyy
set name of (file theName of xxx) to (do shell script "echo " & quoted form of theName & " | sed s'/ (.*)//'")
end repeat
end tell
The code posted by #adayzone will work, but there is no need to use sed for this – plain AppleScript will do, using offset:
set fullString to "Invoice 10.1 (2012) (Digital) (4-Attachments).pdf"
set trimmedString to text 1 thru ((offset of "(" in fullString) - 1) of fullString
-- trim trailing spaces
repeat while trimmedString ends with " "
set trimmedString to text 1 thru -2 of trimmedString
end repeat
this returns “Invoice 10.1". To split the file name into the name and extension, and re-add the extension, you can use System Events’ Disk-File-Folder suite, which will provide the handy name extension property you can store and re-add after trimming the name.
Assuming you use some Automator action to get the files to be processed, the full processing workflow would be to add an AppleScript action after the file selection part with the following code:
repeat with theFile in (input as list)
tell application "System Events"
set theFileAsDiskItem to disk item ((theFile as alias) as text)
set theFileExtension to name extension of theFileAsDiskItem
set fullString to name of theFileAsDiskItem
-- <insert code shown above here>
set name of theFileAsDiskItem to trimmedString & "." & theFileExtension
end tell
end repeat
If you want your Automator workflow to process the files any further, you will also have to create a list of aliases to the renamed files and return that from the AppleScript action (instead of input, which, of course, is not valid anymore).

Resources