I'm trying to make an AppleScript droplet to rename a bunch of images annoyingly formatted, but I found out my AppleScript skills have become nonexistent and I'm getting nowhere. So if possible, full code, not just snippets.
The file setup is always the same, but there are many variations (ex: Yellowst.Nat.Park.D12P55.DMS.3248.jpg)
It starts with a place name, should be a find and replace for a bunch of different strings, ("Yellowst.Nat.Park" -> "Yellowstone National Park")
Then it is followed by two numbers that should be changed in format (D12P55 -> [12x55]). They're always set up in a "D" followed by two numbers, a "P" and again two numbers.
And it ends with a random string, can be numbers, letters etc, which all have to go. They differ in format and length, no pattern in them.
Basically I want to go from "Yellowst.Nat.Park.D12P55.DMS.3248.jpg" to "Yellowstone National Park [02x03] .jpg" I want to add text afterwards so want to end with a space.
The best way to do this seems to me a repetitive find and replace for the first part, Make a list for a bunch of terms wich have to be replaced by a bunch of respective terms. Followed by a detection of the number format and ending with deleting of the random string after it.
Here is another approach.
property pictureFolder : (alias "Mac OS X:Users:Sam:Pictures:test:")
property findList : {"Yellowst.Nat.Park", "Jellyst.Nat.Park"}
property replaceList : {"Yellowstone National Park", "Jellystone \\& National Park"}
tell application "System Events"
set nameList to (name of every file of pictureFolder whose visible = true)
repeat with i from 1 to count of (list folder pictureFolder without invisibles)
set fileName to item i of nameList
set fileExtension to (name extension of (file fileName of pictureFolder))
repeat with j from 1 to count of findList
if fileName contains item j of findList then
set tempName to do shell script "echo " & fileName & " | sed 's/.D\\([0-9][0-9]\\)P\\([0-9][0-9]\\).*/[\\1x\\2] " & i & "." & fileExtension & "/'"
set tempName to do shell script "echo " & tempName & " | sed 's/^" & item j of findList & "/" & item j of replaceList & " /'"
set name of (file fileName of pictureFolder) to tempName
exit repeat
else if j = (count of findList) then
set tempName to do shell script "echo " & fileName & " | sed 's/[.]/ /g'"
set tempName to do shell script "echo " & tempName & " | sed 's/.D\\([0-9][0-9]\\)P\\([0-9][0-9]\\).*/ [\\1x\\2] " & i & "." & fileExtension & "/'"
set name of (file fileName of pictureFolder) to tempName
end if
end repeat
end repeat
end tell
To avoid duplicate names, I added a counter to the end of the file name. If there are no duplicates, you can use this instead:
set tempName to do shell script "echo " & fileName & " | sed 's/.D\\([0-9][0-9]\\)P\\([0-9][0-9]\\).*/[\\1x\\2] " & "." & fileExtension & "/'"
I like small challenges like this Sam. They're fun to me... maybe I'm sick ;). Anyway, I wrote you a handler to clean the file name as you requested. It's not really hard to manipulate text in applescript if you're comfortable with text item delimiters and such. These small challenges keep my text skills sharp.
NOTE: in the nameList property the name must end with a period or whatever character is just before the letter D in the number sequence DxxPxx as you mentioned.
So give this a try. Plug in a variety of fileNames and ensure it works how you want. Of course you need to put more values into the nameList and nameReplaceList properties too.
property nameList : {"Yellowst.Nat.Park."}
property nameReplaceList : {"Yellowstone National Park"}
set fileName to "Yellowst.Nat.Park.D12P55.DMS.3248.jpg"
cleanFilename(fileName)
(*================ SUBROUTINES ================*)
on cleanFilename(fileName)
-- first find the base name and file extension of the file name
set tids to AppleScript's text item delimiters
set ext to ""
if fileName contains "." then
set AppleScript's text item delimiters to "."
set textItems to text items of fileName
set ext to "." & item -1 of textItems
set baseName to (items 1 thru -2 of textItems) as text
set text item delimiters to ""
else
set baseName to fileName
end if
-- next find the pattern D, 2 numbers, P, and 2 numbers in the baseName
set chars to characters of baseName
set theSequence to missing value
repeat with i from 1 to (count of chars) - 6
set thisChar to item i of chars
if thisChar is "d" and item (i + 3) of baseName is "p" then
try
set firstNum to text (i + 1) thru (i + 2) of baseName
firstNum as number
set secondNum to text (i + 4) thru (i + 5) of baseName
secondNum as number
set theSequence to text i through (i + 5) of baseName
exit repeat
end try
end if
end repeat
-- now make the changes
if theSequence is not missing value then
set AppleScript's text item delimiters to theSequence
set theParts to text items of baseName
set fixedFirstPart to item 1 of theParts
repeat with i from 1 to count of nameList
if item i of nameList is fixedFirstPart then
set fixedFirstPart to item i of nameReplaceList
exit repeat
end if
end repeat
set fixedName to fixedFirstPart & " [" & firstNum & "x" & secondNum & "]" & ext
else
set fixedName to fileName
end if
set AppleScript's text item delimiters to tids
return fixedName
end cleanFilename
Now if you want to automate this for a folder full of files you can use this code. Just replace lines 3 and 4 of the above script with this. I didn't check this code but it's simple enough it should work as-is.
NOTE: you don't need to worry if non-image files are in the folder you choose with this code because they won't (I'm assuming this) have the DxxPxx number sequence and thus this script will not change them in any way.
set theFolder to choose folder
tell application "Finder"
set theFiles to files of theFolder
repeat with aFile in theFiles
set thisName to name of aFile
set newName to my cleanFilename(thisName)
if newName is not thisName then
set name of aFile to newName
end if
end repeat
end tell
Related
I have to adjust a lot of files to remove the last part of them:
From this:
108595-1121_gemd_u65_stpetenowopen_em_f_2021-12-03T161809.511773.zip
To this:
108595-1121_gemd_u65_stpetenowopen_em_f.zip
It's always 24 characters that need to be stripped and there is always an underscore at the beginning. The rest is random numbers and characters. I found code below to remove numbers, but I need characters.
My goal is to put this in an automator script with some other processes, but the Renamer in Automator isn't robust enough.
How can I have it strip X-number of characters?
on run {input, parameters}
repeat with thisFile in input
tell application "Finder"
set {theName, theExtension} to {name, name extension} of thisFile
if theExtension is in {missing value, ""} then
set theExtension to ""
else
set theExtension to "." & theExtension
end if
set theName to text 1 thru -((count theExtension) + 1) of theName -- the name part
set theName to (do shell script "echo " & quoted form of theName & " | sed 's/[0-9]*$//'") -- strip trailing numbers
set name of thisFile to theName & theExtension
end tell
end repeat
return input
end run
No need to use do shell script here, which just confuses the issue. Since your names are underscore-delimited, just use AppleScript's text item delimiters:
repeat with thisFile in input
tell application "Finder"
set {theName, theExtension} to {name, name extension} of thisFile
set tid to my text item delimiters
set my text item delimiters to "_"
set nameParts to text items of theName
set revisedNameParts to items 1 through -2 of nameParts
set newName to revisedNameParts as text
set my text item delimiters to tid
if theExtension is not in {missing value, ""} then
set newName to newName & "." & theExtension
end if
set name of thisFile to newName
end tell
end repeat
return input
What this does, in words:
lines 4 and 5 first save the current text item delimiter (TID) value and then set it to '_'
line 6 breaks the name-string into a list of string parts by cutting the name string at the character '_'
line 7 drops the last item in that list (which is everything after the last '_')
line 8 reverses the process, combining the shortened list of text items into a single string by joining them with '_'
The remainder resets the TID value to its original state, adds the extension to the string, and changes the file name
In the image below, I am trying to edit every file name in the cat directory so it only contains one "." For example, I need the first file name to be cat1.jpg and so forth for all of the other file names.
Do any of you all mind providing me some guidance on how I can implement an AppleScript (with Automator?) to rename all of the files in this cat directory?
Let's assume that all the files you want to rename are in a folder on your desktop named "Cat"
This following AppleScript code will remove the first instance of "." ... Leaving an empty space in its place. So, "cat.1.jpg" will be renamed to "cat 1.jpg" etc.
property theFolder : ((path to desktop) as text) & "Cat"
property originalFileName : missing value
property originalFileNameExtension : missing value
tell application "Finder" to set theFiles to (files of folder theFolder) as alias list
repeat with i from 1 to count of theFiles
set thisItem to item i of theFiles
tell application "System Events"
set fileInfo to thisItem's properties
set {originalFileName, originalFileNameExtension} to ¬
{name of fileInfo, name extension of fileInfo}
end tell
set theOffset to offset of originalFileNameExtension in originalFileName
set shortName to text 1 thru (theOffset - 2) of originalFileName
set text item delimiters to "."
set tempText to every text item of shortName
set text item delimiters to " "
set cleanedName to (tempText as text) & "." & originalFileNameExtension
tell application "System Events" to set name of thisItem to cleanedName
end repeat
This would be a full AppleScript solution to your question. But if this is only a one time event for you, mass renaming of the files through Finder, would be a quicker solution.
Answering the question in the title, once you cycle through strings in a repeat loop, to remove the first instance of a string from a string you can:
Use offset:
set s to "foo.bar.txt"
set o to offset of "." in s
set r to (text 1 thru (o - 1) of s) & (text (o + 1) thru -1 of s)
Use Applescript's Text Item Delimiters:
set AppleScript's text item delimiters to "."
set l to text items of s
set r to (item 1 of l) & (text items 2 thru -1 of l as string)
set AppleScript's text item delimiters to ""
I'm trying to make a folder that will automatically create folders then sort the files into them based on the first number. The files I have to sort all come in a similar format with a name like,Feb 4 2.3 U#03 (3).mrd. My intention was to write some AppleScript to create a folder based on the number (2.3) then put all the files with (2.3) into that folder, and do the same with all the other files.
I made a bit that sorts the files based on their number that seems to work,
set text item delimiters to {" "}
tell application "Finder"
set aList to every file in folder "Re-namer"
repeat with i from 1 to number of items in aList
set aFile to (item i of aList)
try
set fileName to name of aFile
set firstPart to text item 1 of fileName
set secondPart to text item 2 of fileName
set thirdPart to text item 3 of fileName
set fourthPart to text item 4 of fileName
set fifthPart to text item 5 of fileName
set newName to thirdPart & " " & secondPart & " " & firstPart & " " & fourthPart & " " & fifthPart
set name of aFile to newName
end try
end repeat
end tell
now I just need to create the new folders based on the first number and put the matching files in. I tried to make a script for this too (keep in mind I've never coded before and have no idea what I'm doing) and unsurprisingly it didn't work :(
tell application "Finder"
open folder "Re-namer"
set loc to folder "Re-namer"
set aList to every file in loc
repeat with i from 1 to number of items in aList
set aFile to (item i of aList)
if not (exists folder named "text item 1" in loc) then
make new folder in loc with properties {name:"text item 1"}
else
move aFile in folder "text item 1"
end if
end repeat
end tell
I've found a few similar questions but I still can't get it to work. If anyone has any ideas or resoures to help with this question I would greatly appreaate it.
Your are very close to correct script. However, instead of doing 2 loops, one for changing names and one to move files, it is quicker to do only 1 loop doing both at same time.
Also, the key thing is to understand that, in the loop, if you change the name, the Finder loose the reference to the file changed, then it fails when you try to move it after changing name. but since you know the folder and the new name, you can still reference to that "new" file.
set MyRenamer to choose folder "Select the folder"
set TPath to MyRenamer as string
set text item delimiters to {" "}
tell application "Finder"
set aList to every file in MyRenamer
repeat with F in aList
set fileName to name of F
set firstPart to text item 1 of fileName -- like "Feb"
set secondPart to text item 2 of fileName -- like "4"
set thirdPart to text item 3 of fileName -- like "2.3"
set fourthPart to text item 4 of fileName -- like "U#03"
set fifthPart to text item 5 of fileName -- like "(3).mrd"
set newName to thirdPart & " " & secondPart & " " & firstPart & " " & fourthPart & " " & fifthPart
set name of F to newName
if (not (exists folder thirdPart in MyRenamer)) then
make new folder in MyRenamer with properties {name:thirdPart}
end if
move (TPath & newName) as alias to folder (TPath & thirdPart & ":") -- rebuild the new file path as alias and move it.
end repeat
end tell
Tested and OK.
I'm trying to write all the song names my iTunes to a txt document. The first issue I had was that I can't seem to correctly loop the operation. Here is my test case with the first 15 songs in my iTunes:
tell application "TextEdit"
make new document
end tell
tell application "iTunes"
set trNameID1 to name of track 1
set trNameID2 to name of track 2
set trNameID3 to name of track 3
set trNameID4 to name of track 4
set trNameID5 to name of track 5
set trNameID6 to name of track 6
set trNameID7 to name of track 7
set trNameID8 to name of track 8
set trNameID9 to name of track 9
set trNameID10 to name of track 10
set trNameID11 to name of track 11
set trNameID12 to name of track 12
set trNameID13 to name of track 13
set trNameID14 to name of track 14
set trNameID15 to name of track 15
tell application "TextEdit"
set text of document 1 to {trNameID1 & "
", trNameID2 & "
", trNameID3 & "
", trNameID4 & "
", trNameID5 & "
", trNameID6 & "
", trNameID7 & "
", trNameID8 & "
", trNameID9 & "
", trNameID10 & "
", trNameID11 & "
", trNameID12 & "
", trNameID13 & "
", trNameID14 & "
", trNameID15} as text
end tell
end tell
When I try to loop it, the txt document only contains the last song name, for instance:
tell application "TextEdit"
make new document
end tell
tell application "iTunes"
set trNum to 1
repeat 15 times
set trNameID to name of track (trNum)
tell application "TextEdit"
set text of document 1 to trNameID & "
"
end tell
end repeat
end tell
This will only output the fifteenth song's name onto the txt document.
I realize that this may be very basic, but I have literally been using applescript for about 48 hours, and I can't seem to figure this out. I would like all of the song names to be in a txt document so I can read and analyze the strings in c++. Does anyone have any ideas?
Also, I'm not sure if there is a way, in AppleScript, to look at the entire iTunes library and see the last song, record that song's id in iTunes, and then make a repeat loop that goes through that id. This way the loop would work for exactly the number of songs that are in the library.
Any ideas would be very much appreciated!
You don't really need a repeat loop at all. You can get track names directly from iTunes. You get it in list format so we just convert that list into a string separating the list items with a return character. Then we write it to TextEdit. So this code optimizes #Michele Percich's code by eliminating the repeat loop and using applescript's text item delimiters to convert the list to a string for use in TextEdit.
tell application "iTunes"
set trackNames to name of every track in (first playlist whose special kind is Music)
end tell
set text item delimiters to return
set trackNames to trackNames as text
set text item delimiters to ""
tell application "TextEdit"
make new document
set text of document 1 to trackNames
end tell
You need to increment the value of trNum variable at the end of your repeat loop:
set trNum to trNum + 1
Or better use a different repeat syntax:
repeat with trNum from 1 to 15
And also to add (and not replace) the track name to the document:
set text of document 1 to text of document 1 & trNameID & return
However, this probably is a better way to do what you want:
tell application "iTunes"
set trackList to ""
set allTracks to every track in (first playlist whose special kind is Music)
repeat with currentTrack in allTracks
set trNameID to name of currentTrack
set trackList to trackList & trNameID & return
end repeat
end tell
tell application "TextEdit"
make new document
set text of document 1 to trackList
end tell
i see you all use the:
tell application "TextEdit"
make new document
set text of document 1 to trackNames
end tell
command
You can use a faster way:
set textlocation to "/users/yourusername/desktop/test.txt"
set Line_1 to "Hello this is line one, if you want more lines just copy > this script and change the variables."
do shell script "echo " & quoted form of Line_1 & " >> " & quoted form of textlocation
You can see in the script the 2 ">>" signs, this will add each textline in a new line in a txt file.
If there is only one ">" the text will replace the other text.
Here is an example:
First with 2 ">>" lines
do shell script "echo Hey this is one line. >> /Users/Yourusername/desktop/Add.txt"
do shell script "echo And this is the second one. >> /Users/Yourusername/desktop/Add.txt"
This script will make a txt file like this:
Hey this is one line.
And this is the second one.
Now with 2 ">" lines
do shell script "echo Hey this is one line > /Users/Zl109819/desktop/Add.txt"
do shell script "echo And this is the second one > /Users/Zl109819/desktop/Add.txt"
This script will make a txt file like this:
And this is the second one.
I can get the names of all files in a folder by doing this:
tell application "Finder"
set myFiles to name of every file of somePath
end tell
How can I change the strings in myFiles so that they do not include the file extension?
I could for example get {"foo.mov", "bar.mov"}, but would like to have {"foo", "bar"}.
Current solution
Based on the accepted answer I came up with the code below. Let me know if it can be made cleaner or more efficient somehow.
-- Gets a list of filenames from the
on filenames from _folder
-- Get filenames and extensions
tell application "Finder"
set _filenames to name of every file of _folder
set _extensions to name extension of every file of _folder
end tell
-- Collect names (filename - dot and extension)
set _names to {}
repeat with n from 1 to count of _filenames
set _filename to item n of _filenames
set _extension to item n of _extensions
if _extension is not "" then
set _length to (count of _filename) - (count of _extension) - 1
set end of _names to text 1 thru _length of _filename
else
set end of _names to _filename
end if
end repeat
-- Done
return _names
end filenames
-- Example usage
return filenames from (path to desktop)
From http://www.macosxautomation.com/applescript/sbrt/index.html :
on remove_extension(this_name)
if this_name contains "." then
set this_name to ¬
(the reverse of every character of this_name) as string
set x to the offset of "." in this_name
set this_name to (text (x + 1) thru -1 of this_name)
set this_name to (the reverse of every character of this_name) as string
end if
return this_name
end remove_extension
Single line way of doing it, no Finder, no System Events. So more efficient and faster. Side effect (could be good, or bad): a file name ending with "." will have this character stripped out. Using "reverse of every character" makes it works if the name as more than one period.
set aName to text 1 thru ((aName's length) - (offset of "." in ¬
(the reverse of every character of aName) as text)) of aName
The solution as a handler to process a list of names:
on RemoveNameExt(aList)
set CleanedList to {}
repeat with aName in aList
set the end of CleanedList to text 1 thru ((aName's length) - (offset of ¬
"." in (the reverse of every character of aName) as text)) of aName
end repeat
return CleanedList
end RemoveNameExt
Here's an applescriptish method to get Finder's idea of what the stripped filename is but please note it will only work if you have NOT enabled the option in Finder's preferences to "Show all filename extensions":
set extension hidden of thisFile to true
set thisName to displayed name of thisFile
-- display dialog "hey"
set extension hidden of thisFile to false
Here's a full script that does what you wanted. I was reluctant to post it originally because I figured there was some simple one-liner which someone would offer as a solution. Hopefully this solution is not a Rube Goldberg way of doing things.
The Finder dictionary does have a name extension property so you can do something like:
tell application "Finder"
set myFiles to name extension of file 1 of (path to desktop)
end tell
So the above will get you just the extension of the first file on the user's desktop. It seems like there would be a simple function for getting the (base name - extension) but I didn't find one.
Here's the script for getting just the filenames without extension for every file in an entire directory:
set filesFound to {}
set filesFound2 to {}
set nextItem to 1
tell application "Finder"
set myFiles to name of every file of (path to desktop) --change path to whatever path you want
end tell
--loop used for populating list filesFound with all filenames found (name + extension)
repeat with i in myFiles
set end of filesFound to (item nextItem of myFiles)
set nextItem to (nextItem + 1)
end repeat
set nextItem to 1 --reset counter to 1
--loop used for pulling each filename from list filesFound and then strip the extension
--from filename and populate a new list called filesFound2
repeat with i in filesFound
set myFile2 to item nextItem of filesFound
set myFile3 to text 1 thru ((offset of "." in myFile2) - 1) of myFile2
set end of filesFound2 to myFile3
set nextItem to (nextItem + 1)
end repeat
return filesFound2
Though the above script does work if anyone knows a simpler way of doing what the OP wanted please post it cause I still get the sense that there should be a simpler way of doing it. Maybe there's a scripting addition which facilitates this as well. Anyone know?
Based on Lauri Ranta's nice solution, which works for extensions that Finder doesn't know about:
set delims to AppleScript's text item delimiters
set AppleScript's text item delimiters to "."
set myNames to {}
tell application "Finder"
set myFiles to name of every file of (path to Desktop)
repeat with myfile in myFiles
set myname to name of file myfile
if myname contains "." then set myname to (text items 1 thru -2 of myname) as text
set end of myNames to myname
end repeat
end tell
set AppleScript's text item delimiters to delims
return myNames
I don't know how to remove the extensions when you use the "every file"
syntax but if you don't mind looping (loop not shown in example) through each file then this will work:
tell application "Finder"
set myFile to name of file 1 of somePath
set myFile2 to text 1 thru ((offset of "." in myFile) - 1) of myFile
end tell
Within a tell "Finder" block this collects file names stripped of the extension in myNames:
repeat with f in myFiles
set myNames's end to ¬
(f's name as text)'s text 1 thru -(((f's name extension as text)'s length) + 2)
end repeat
For a single file I found the answer here, copied below.
set theFileName to "test.jpg"
set thePrefix to text 1 thru ((offset of "." in theFileName) - 1) of theFileName
This is a little more than you need, but it will handle more than one "." in a file name.
Assuming that a file alias is passed in to the method.
on Process(myFileAlias)
set myFile to myFileAlias as string
set AppleScript's text item delimiters to ":"
set myItemCount to the number of text items in myFile
set myFileName to the last text item of myFile
set myFilePath to text items 1 through (myItemCount - 1) of myFile
set AppleScript's text item delimiters to "."
set myItemCount to the number of text items in myFileName
set myExtension to the last text item of myFile
// This line is the key.
set myShortFilename to text items 1 through (myItemCount - 1) of myFileName as string
log (myFileName)
log (myShortFilename)
end