Finding and listing all subfolders but nothing else - shell

I am trying to make a looping script that will take a parent folder and find all the sub folders. This way I can take them one at a time and run a second script on them.
This would work if I was looking for text files. I want to try to use it for find just folders but don't know how to and can't find anything in that direction.
-- Search for Subfolder
set ParentPath to choose folder
set allFiles to (do shell script "find " & quoted form of POSIX path of ParentPath & " -iname \"*.eps\""))
-- Process files
repeat with nFile in allFiles
my runScript(nFile)
end repeat
In theory it would be this.
-- Search for Subfolder
set ParentPath to choose folder
set allFiles to all folders inside ParentPath
-- Process files
repeat with nFile in allFiles
my runScript(nFile)
end repeat
Thanks!

With bash, you'd say:
shopt -s globstar nullglob
# the trailing slash below restricts matches to directories.
for dir in **/; do
some command with "$dir"
done
This recursively finds all directories under the current directory. If you're only looking for subdirectories of the current dir: for dir in */

find <dirname> -type d > subdirlist
You don't need to specify depth levels for find, either; it will keep going down to the end. You actually only specify a max depth if you don't want it to go too far.
You can use a find loop as the basis for your processing script, as well. As one example:-
find *.mp3 d.mp3 -type f | while read mp3s
do
echo $mp3s
<more commands>
done

Just try below:
find ./ -type d

Found this works perfectly.
set ParentPath to (choose folder) as string
set FolderList to {}
tell application "System Events"
set ItemList to disk items of folder ParentPath
repeat with CurrentItem in ItemList
if (class of CurrentItem) = folder then
set end of FolderList to ((path of CurrentItem) as alias)
end if
end repeat
end tell

Related

Check file name for range of characters

Is there a way to tell Applescript to locate a file where the file name would match this type of criteria:
set foundFile to file whose name starts with
[character 0-9] followed by [character 0-9] followed by underscore
I can't think of a way to do it with a Finder whose clause statement. However grep has regular expression capabilities so try this...
set theFolder to choose folder
set foundFileNames to paragraphs of (do shell script "ls " & quoted form of POSIX path of theFolder & " | grep '^[0-9][0-9]_'")
set firstFoundFile to (theFolder as text) & item 1 of foundFileNames
Here's a handler that does this with all Applescript and no shell script.
-- get your folder however and feed the folder to the handler getMatchingFiles(*your folder*)
on getMatchingFiles(theFolder)
tell application "Finder"
set theFiles to every file of theFolder
set allDigits to "0123456789"
set matchingFiles to {}
repeat with aFile in theFiles
set fileName to the name of aFile
if ((the first character of fileName is in allDigits) and (the second character of fileName is in allDigits) and (the third character of fileName is "_")) then copy aFile to the end of matchingFiles
end repeat
end tell
return matchingFiles
end getMatchingFiles
regulus6633's answer is promising, but there's no need to resort to resort to external utilities ls and grep; the shell's own pathname expansion (globbing) is sufficient, using pattern [0-9][0-9]_*:
# Pick a folder.
set targetFolder to choose folder
# Get matching files.
# `shopt -s nullglob` instructs the shell to return an empty string, if no files match.
set foundFiles to paragraphs of (do shell script "shopt -s nullglob; printf '%s
' " & quoted form of POSIX path of targetFolder & "[0-9][0-9]_*")
# Extract the 1st matching file.
set foundFile to item 1 of foundFiles

Applescript - move files to folder which name begins with first 7 characters of filename

I've got 2 folders
the first folder contains all the files which I'd like to move to a subfolder of the second folder. I'd like to this based on the first 7 characters of both the file & folder names.
So if the first 7 characters of the subfolder in FOLDER 2 matches the first 7 characters of the file in FOLDER 1. The file get's moved into the subfolder of FOLDER 2
Right now I've got an Applescript which works, but it's terribly slow.
Here's the script so far:
set mgFileList to ""
set mgDestFolder to ""
set mgFilesFolder to (choose folder with prompt "Where are the files stored which you would like to move to the destination?")
set mgDestFolder to (choose folder with prompt "Where is the destination folder?")
set folderList to contents of mgDestFolder
tell application "Finder" to set fileList to files of mgFilesFolder
repeat with aFile in fileList
set prefix to getPrefix(name of aFile)
tell application "Finder"
try
set destinationFolder to (1st folder of mgDestFolder whose name begins with prefix)
move aFile to destinationFolder
end try
end tell
end repeat
on getPrefix(aName)
set prefix to text 1 thru 7 of aName
return prefix
end getPrefix
I've only recently got into Applescripting. Can this be done more efficiently within Applescript? I've searched around for a solution which works with a shell script (which I think will probably be a lot faster), but haven't been able to get any of them working.
I'm working on OSX Mountain Lion 10.8.4
--
edit
I see that I've uploaded the wrong version of the script I've managed to put together so far. Above is the script that is working, but it's really slow. Probably because it doesn't use any shell script.
---------------update-------------------
Here is the final script that is working pretty fast right now:
set mgFilesFolder to choose folder with prompt "Where are the files stored which you would like to move to the destination?"
set mgDestFolder to choose folder with prompt "Where is the destination folder?"
tell application "System Events"
set fileList to files of mgFilesFolder whose name does not start with "."
repeat with aFile in fileList
set prefix to my getPrefix(name of aFile)
try
set destinationFolder to (1st folder of mgDestFolder whose name begins with prefix)
move aFile to POSIX path of destinationFolder
end try
end repeat
end tell
on getPrefix(aName)
try
set prefix to text 1 thru 7 of aName
return prefix
on error
return aName
end try
end getPrefix
The Finder is generally a slow program because it does a lot of things on your computer. Therefore you should avoid using it if possible. In your case these tasks can be done using System Events. Try this, maybe it will be faster. Note that you had a couple mistakes in your code which are fixed in this code.
set mgFilesFolder to choose folder with prompt "Where are the files stored which you would like to move to the destination?"
set mgDestFolder to choose folder with prompt "Where is the destination folder?"
tell application "System Events"
set fileList to files of mgFilesFolder whose name does not start with "."
repeat with aFile in fileList
set prefix to my getPrefix(name of aFile)
try
set destinationFolder to (1st folder of mgDestFolder whose name begins with prefix)
move aFile to POSIX path of destinationFolder
end try
end repeat
end tell
on getPrefix(aName)
try
set prefix to text 1 thru 7 of aName
return prefix
on error
return aName
end try
end getPrefix
Not sure how many files you're working with, but I tested this with 10 folders and ~100 files, and it took less than 4 seconds to run. Working with strings is much faster than working with files, so the script gets the files/folders as strings and builds aliases when they're needed.
set mgFilesFolder to (choose folder with prompt "Where are the files stored which you would like to move to the destination?")
set mgDestFolder to (choose folder with prompt "Where is the destination folder?")
--Always use System Events whenever possible. It's WAY faster than Finder.
tell application "System Events"
set folderList to name of folders of mgDestFolder
set fileList to name of files of mgFilesFolder
end tell
repeat with i from 1 to (count folderList)
set folderName to item i of folderList
set filesToMove to {}
repeat with j from 1 to (count fileList)
set filename to item j of fileList
if filename begins with folderName then
set end of filesToMove to alias ((mgFilesFolder as string) & filename)
end if
end repeat
--Can't use system events for moving files. You have to use Finder.
tell application "Finder"
move filesToMove to alias ((mgDestFolder as string) & folderName & ":")
end tell
end repeat
It might be easier to use shell scripting:
cd FOLDER1; for f in *; do d=../FOLDER2/"${f:0:7}"*; [[ -d $d ]] && mv "$f" "$d"; done

AppleScript to read text file containing file names, search for each file name, and if a file is found copy it to a folder

Sorry to ask a question without even pasting my coding attempt, but I've never used AppleScript before and I have no idea how I would do this. I've found bits of code online that do small parts of each step of this, but some of the key parts I can't figure out how to do. If I can get this figured out it would save a lot of time. Basically my problem is that a client sent over thousands of photos, all in multiple levels of sub folders, along with an Excel document containing about 300 file names that I need to pull out and use. I can copy the file names from the Excel document into a plain text file, either multi-line or comma separated.
So this is what I need to do:
Open folder selector dialog to select the destination folder
Open file selector dialog to select the text file
Loop through each line (or comma separated value) of the text file
Take that string and search for a file name containing the string
Copy the first result into a folder (let's say Desktop:Found Photos)
If a file could not be found matching the string then add the search string into a text file (so I could email it to the client and ask them to send it to me)
If you can't code this whole process, if you could help me with looping through the text file, searching for the file name and copying the first result to another folder, and adding the file name to a text file if a file wasn't found, then I could probably piece it it all together. Thanks for any help.
You can try something along the lines of:
set newFolder to POSIX path of (path to desktop as text) & "Found Photos"
do shell script "mkdir -p " & quoted form of newFolder
set filePaths to paragraphs of (read (choose file with prompt "Select file list") as «class utf8»)
set fileFolder to POSIX path of (choose folder with prompt "Select folder containing files")
set foundFiles to {}
repeat with fileName in filePaths
set fileName to (contents of fileName)
set xxx to do shell script "find " & quoted form of fileFolder & " -name " & quoted form of fileName
if xxx ≠ "" then
tell application "System Events" to move file xxx to newFolder
set end of foundFiles to fileName & return
end if
end repeat
set foundFiles to (foundFiles as text)
do shell script "echo " & quoted form of foundFiles & " > " & quoted form of POSIX path of ((path to desktop as text) & "FoundFiles.txt")
It might have been easier to use shell scripting:
IFS=$'\n'
mkdir -p ~/Desktop/target/
for l in $(cat ~/Desktop/files.txt); do
found=$(find ~/Documents/source -type f -name "*$l*")
[[ -n $found ]] && cp $found ~/Desktop/target/ || echo "$l"
done

Find absolute paths to folder contents

Another newbie applescript question. I'm trying to get absolute paths to all of the folders and files inside of a folder upon opening it. I'd like to write something like
on opening folder this_folder
tell application "Finder"
set everyPath to POSIX path of every item in entire contents of this_folder
end tell
repeat with n from 1 to count of everyPath
display dialog item n of everyPath
end repeat
end opening folder
But this s***s a brick so right now I have this even uglier mess.
on opening folder this_folder
tell application "Finder"
set everyName to name of every item in entire contents of this_folder
set everyPath to {}
repeat with n from 1 to count of everyName
set end of everyPath to POSIX path of item n of everyName
end repeat
end tell
repeat with n from 1 to count of everyPath
display dialog item n of everyPath
end repeat
end opening folder
Which diplays dialogs like '/file.ext' when I'm looking for something more like 'User/username/documents/folder/file.ext' and 'User/username/documents/folder/subfolder/file2.ext'.
Judging by my tendency to miss the obvious in the past, I'm assuming there's an easy way to get full path names that I'm just oblivious to, and I would appreciate any help in sorting it out. Thanks!
You can't do it the way you're trying. Normally you can just add the folder path to a name to get the full path. However you're also getting names of files in sub folders, so that won't work because you don't know the subfolder paths. As such getting names from the Finder won't help you. A faster method than the Finder for something like this may be to use the unix program "find".
set this_folder to path to desktop
-- we have to remove the trailing / from the folder path so the
-- returned paths from the find command are correct
set posix_folder to text 1 thru -2 of (POSIX path of this_folder)
-- use find to quickly find the items in this_folder
-- also filter out invisible files and files in invisible folders
-- also filter files inside of package files like ".app" files
set theItems to paragraphs of (do shell script "find " & quoted form of posix_folder & " -name \"*.*\" ! -path \"*/.*\" ! -path \"*.app/*\" ! -path \"*.scptd/*\" ! -path \"*.rtfd/*\" ! -path \"*.xcodeproj/*\"")
And if the find command isn't appropriate then you could use the mdfind command (e.g.. spotlight through the command line) in a similar manner.

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