Use Automator/Applescript to crop filenames after certain character? - applescript

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).

Related

Applescript to create folders and download files from weblink to those created folders based on .CSV values

In my example .CSV file, I have a column A with the following values: 2,2,5,5,5. In column B are hyperlinks to corresponding files that require downloading: http://example.com/2A.pdf, http://example.com/2B.pdf, http://example.com/5A.pdf, http://example.com/5B.pdf, http://example.com/5BC.pdf. Having difficulty creating an applescript that creates the DL folder (based on the non-unique column A value) and applies the DLs of any corresponding row to the appropriate folder. Any help would be greatly appreciated! TIA.
From your description, I am assuming the CSV file looks something like this:
2, http://example.com/2A.pdf
2, http://example.com/2B.pdf
5, http://example.com/5A.pdf
5, http://example.com/5B.pdf
5, http://example.com/5BC.pdf
and that the file 2A.pdf should end up in a directory called 2.
Assuming I have interpreted this correctly, here is the AppleScript that will achieve this (replace /Path/To/Save/Folder/ with the full path to the folder where these new files and folders will be downloaded, and /Path/To/File.csv to the full path of the CSV file):
-- Note: The ending / is essential in BaseDir
set BaseDir to POSIX file "/Path/To/Save/Folder/"
set rows to every paragraph of (read "/Path/To/File.csv")
set AppleScript's text item delimiters to {"/"}
set [TopDir, BaseFolder] to [text items 1 thru -3, text item -2] of ¬
POSIX path of BaseDir
-- Create initial base folder if it doesn't exist
tell application "Finder" to if not (exists BaseDir) then ¬
make new folder in (TopDir as text as POSIX file) ¬
with properties {name:BaseFolder}
-- This will prevent EOF-related errors
-- Thanks to #user3439894 for highlighting the need for this
set rows to reverse of rows
if the number of words of the first item in rows is 0 ¬
then set rows to the rest of rows
repeat with row in rows
set [N, |url|] to [first word, text items -2 thru -1] of row
-- Create folder into which file will be downloaded
tell application "Finder" to if not (exists [BaseDir, N] as text) then ¬
make new folder in BaseDir with properties {name:N}
-- This is the shell command that downloads the file
-- e.g. "cd '/Users/CK/Desktop/example.com/5'; curl example.com/5BC.pdf \
-- remote-name --silent --show-error"
set command to ("cd " & ¬
quoted form of POSIX path of ([BaseDir, N] as text) & ¬
"; curl " & |url| as text) & ¬
" --remote-name --silent --show-error"
-- Run the shell command
do shell script command
end repeat
-- Open folder in Finder upon completion of downloads
tell application "Finder"
activate
open BaseDir
end tell
I should highlight that this is not a robust script intended for general use that would work across situations, but rather an example script that is tailored specifically to the case described. If your CSV file differs even slightly from my assumed format, errors are likely to occur.

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

Automator/AppleScript to find same file name with different extension in same directory

I'd like to create an automator action to help manage DNG/XMP files. I'd like to be able to drag a DNG (or several) onto the action which will send the DNG and the matching XMP file to the trash. The files have the same name except for the extension, they are in the same directory. For example, IMGP1361.DNG and IMGP1361.xmp
This would be a simple task for a shell script, but is there an Automator way to do it (to learn more about Automator)? Is there a way to get at the file name of the input finder item, change it in a variable and use that as input to another action?
Thanks.
This script for Automator will delete all of the files that share the same prefix and whose name extension is listed in the grep command. You may add additional extensions as well. (xmp|DNG|pdf|xls)
on run {input, parameters}
try
repeat with anItem in input
tell (info for anItem) to set {theName, theExt} to {name, name extension}
set shortName to text 1 thru ((get offset of "." & theExt in theName) - 1) of theName
tell application "Finder"
set parentFolder to parent of anItem as alias
set matchList to every paragraph of (do shell script "ls " & POSIX path of parentFolder & " | grep -E '" & shortName & ".(xmp|DNG)'")
delete (every file of parentFolder whose name is in matchList)
end tell
end repeat
end try
end run
OK, got it. You can use the AppleScript given below inside an Automator workflow like this:
For every selected file in the Finder, if its extension is in ext_list, it will be moved to the Trash, and so will all other files of the same name in the same folder whose extension is one of those in also_these_extensions.
It can be useful, e.g. also for cleaning a folder with auxiliary LaTeX files: just put "tex" into ext_list and all the other extensions (such as "aux", "dvi", "log") into also_these_extensions.
The selected files don't need to be inside the same folder; you can also select several items in a Spotlight search results window.
on run {input, parameters}
-- for every item having one of these extensions:
set ext_list to {"dng"}
-- also process items with same name but these extensions:
set other_ext_list to {"xmp"}
tell application "Finder"
set the_delete_list to {}
set delete_list to a reference to the_delete_list
-- populate list of items to delete
repeat with the_item in input
set the_item to (the_item as alias)
if name extension of the_item is in ext_list then
copy the_item to the end of delete_list
set parent_folder to (container of the_item) as alias as text
set item_name to text 1 thru ((length of (the_item's name as text)) - (length of (the_item's name extension as text))) of (the_item's name as text)
repeat with ext in other_ext_list
try
copy ((parent_folder & item_name & ext) as alias) to the end of delete_list
end try
end repeat
end if
end repeat
-- delete the items, show info dialog
move the_delete_list to the trash
display dialog "Moved " & (length of the_delete_list) & " files to the Trash." buttons {"OK"}
end tell
end run

How find the file name of an executing AppleScript

How do I find the name of an executing AppleScript?
REASON: I want to create a script that changes its behavior based on its filename. Something like:
if myname is "Joe" then ACTION1
else if myname is "Frank" then ACTION2
else ACTION3
The normal way to get the name is by using "name of me". However applescripts are run by applescript runner so when you use that on a script you get "Applescript Runner" as the name. If you compile your script as an application then "name of me" will work. The only way to get the script name is by getting its path and extracting the name. Something like this would thus work for scripts...
getMyName()
tell me to display dialog result
on getMyName()
set myPath to path to me as text
if myPath ends with ":" then
set n to -2
else
set n to -1
end if
set AppleScript's text item delimiters to ":"
set myName to text item n of myPath
if (myName contains ".") then
set AppleScript's text item delimiters to "."
set myName to text 1 thru text item -2 of myName
end if
set AppleScript's text item delimiters to ""
return myName
end getMyName
Here's a method that works for all of the following:
*.scpt files (compiled AppleScript files; run in AppleScript Editor or with osascript)
*.applescript files (uncompiled AppleScript files; run in AppleScript Editor or with osascript)
command-line scripts that directly contain AppleScript (marked as executable and starting with #!/usr/bin/env osascript):
*.app files created with AppleScript Editor
*.app files created with Automator that contain AppleScript actions
Note: By contrast, it does not work for the following:
OS X services created with Automator that contain AppleScript actions (special *.workflow files) - always reports 'WorkflowServiceRunner[.xpc]'
general-purpose *.workflow files created with Automator that contain ApplesScript actions and that are run with automator - always reports 'Automator Runner[.app]'
Get the name of the running script, including filename extension (.scpt, .app, or .applescript, as the case may be):
tell application "System Events" to set myname to get name of (path to me)
If you want to remove the filename extension with a single command, use the following, do shell script-based approach:
tell application "System Events" to set myname to do shell script "rawName=" & quoted form of (get name of (path to me)) & "; printf '%s' \"${rawName%.*}\""
Here's an all-AppleScript alternative that is more verbose (yet concise by AppleScript standards):
tell application "System Events"
set myname to name of (path to me)
set extension to name extension of (path to me)
end tell
if length of extension > 0 then
# Make sure that `text item delimiters` has its default value here.
set myname to items 1 through -(2 + (length of extension)) of myname as text
end if
Finally, here's a variation: a subroutine that you can call with set myname to getMyName():
on getMyName()
local myName, tidSaved
tell application "System Events"
set myAlias to path to me -- alias to the file/bundle of the running script
set myName to name of myAlias -- filename with extension, if any.
if name extension of myAlias is not "" then -- strip away extension
set {tidSaved, AppleScript's text item delimiters} to {AppleScript's text item delimiters, {""}}
set myName to items 1 through -(2 + (length of (get name extension of myAlias))) of myName as text
set AppleScript's text item delimiters to tidSaved
end if
end tell
return myName
end getMyName
An easier way to find out the base part of the path is using name of:
tell application "Finder"
set p to path to me
set nam to name of file p as text
end tell
Maybe this:
set appname to name of current application

Getting the file name of files dropped on the script

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

Resources