Set list to shell script output in AppleScript - shell

I have a shell script that outputs filenames (one per line). I want to put that output into a list in AppleScript.
How can I do this?
Bonus points for how to then turn those filename strings into file objects.
EDIT:
When trying this:
set theFiles to {}
repeat with i from 1 to count of filenames
set end of theFiles to (POSIX file (item i of filenames))
end repeat
I get this:
error "Finder got an error: Can’t get POSIX file \"/path/to/file\"." number -1728 from file "Macintosh HD:path:to:file"
EDIT-2:
Turns out finder isn't aware of a file that gets created after the "tell" statement starts. How do I update it or make it aware of the new file?
EDIT-3:
This worked (note the addition of "my"):
set theFiles to {}
repeat with i from 1 to count of filenames
set end of theFiles to (my POSIX file (item i of filenames))
end repeat

set myFilenamesList to paragraphs of (do shell script "path/to/shell/script")
set firstFileObject to POSIX File (item 1 of myFilenamesList)
When you have a list, you use a repeat loop to iterate over the list and do something with the items in the list. For example if you wanted a list of the file objects you could do this.
set fileObjectsList to {}
repeat with i from 1 to count of myFilenamesList
set end of fileObjectsList to POSIX File (item i of myFilenamesList)
end
return fileObjectsList
Of course it doesn't make much sense to do this because once you have the file objects in a list then you'll need to repeat over that list to do something with those objects... thus you'll be repeating over a list 2 times when 1 time would probably suffice. So I would do something like this instead...
repeat with i from 1 to count of myFilenamesList
set thisFileObject to POSIX File (item i of myFilenamesList)
-- do something with the file object "thisFileObject"
end

Related

AppleScript - array read from disk is empty

I have a script that starts like this:
tell application "Finder"
set theFolder to (choose folder)
set theFile to POSIX path of ((theFolder as string) & "words.txt")
set fileHandle to open for access theFile
set nameArray to paragraphs of (read fileHandle for (get eof fileHandle) as «class utf8»)
close access fileHandle
end tell
File words.txt is there and contains one word per line.
theFile is a valid path to words.txt, something like /Users/myself/Desktop/folder/words.txt.
nameArray comes empty.
Why?
If instead of letting the user choose the folder, I hardcode the path, like
set theFile to "/Users/myself/Desktop/folder/words.txt"
everything works fine.
First of all, you do not need Finder as the necessary commands are just basic AppleScript commands and or are all a part of Standard Additions.
The following three lines, by themselves, will do what you are trying to do:
set theFolder to (choose folder)
set theFile to POSIX path of ((theFolder as string) & "words.txt")
set nameArray to paragraphs of (read theFile as «class utf8»)
Something to keep in mind, if the last line in the file ends with a line feed then the last item in the list will be "" and you can either account for this in your code as you use each item of the list or add the following example to remove it if it exists:
if last item of nameArray is equal to "" then ¬
set nameArray to items 1 thru -2 of nameArray

AppleScript Get data from log

I need my AppleScript to find some data from a log (text) and set as a value
e.g Serial ID : XXXXXX , devices : XXXXX
Also the app is generating a lot of log files, so I need to take the data from the most recent logs.
Is that even possible
set listOfShows to {}
set Shows to paragraphs of (read POSIX file "Users/username/Library/Logs/app/Applicationc1454545.log.log")
repeat with nextLine in Shows
if length of nextLine is greater than 0 then
copy nextLine to the end of listOfShows
end if
end repeat
choose from list listOfShows/
Maybe I can get the file with this :
set sourceFolder to POSIX file "/Users/Users/Library/Logs/"
tell application "Finder"
sort (get files of folder sourceFolder) by creation date
-- This raises an error if the folder doesn't contain any files
set theFile to (item 1 of result) as alias
end tell
Actually when you sort by creation date in Finder the most recent file is the last rather than the first file.
The error occurs if there are no files and therefore no item 1.
Try this:
path to library folder from user domain is the relative path to the library folder of the current user.
set logFolder to (path to library folder from user domain as text) & "Logs:"
tell application "Finder" to set sortedFiles to sort (get files of folder logFolder whose name contains "Applicationc1454545") by creation date
if sortedFiles is not {} then
set mostRecentLogFile to last item of sortedFiles as alias
set listOfShows to {}
set Shows to paragraphs of (read mostRecentLogFile as «class utf8»)
repeat with nextLine in Shows
if length of nextLine is greater than 0 then
copy nextLine to the end of listOfShows
end if
end repeat
set chosen to choose from list listOfShows
if chose is false then return
set chosen to item 1 of chosen
end if

Delete multiple files with applescript

Let’s say I have multiple files I want to delete, and they’re stored one per line in a files.txt file. I can delete them with
set deleteThis to paragraphs of (read "files.txt")
repeat with lineFromFile in deleteThis
set fileName to POSIX file lineFromFile
tell application "Finder" to delete file fileName
end repeat
This is the logic you usually find online — deleting them one by one, but not only does this screw your “Put Back” option (you have to ⌘z multiple times), it also plays the trash sound a bunch of times in a row.
Is there a way to delete multiple files at once, say via storing them in an array and deleting that?
Edit
The answer by #adayzdone is the best so far, but it fails on directories
Try:
set deleteThis to paragraphs of (read "files.txt" as «class utf8»)
set deleteList to {}
tell application "Finder"
repeat with aPath in deleteThis
try
set end of deleteList to (file aPath)
on error
try
set end of deleteList to (folder aPath)
end try
end try
end repeat
delete deleteList
end tell
Yes, Finder will take a list of paths as an argument to the delete command.
set deleteThis to paragraphs of (read "files.txt")
repeat with i from 1 to (count deleteThis)
set item i of deleteThis to POSIX file (item i of deleteThis)
end repeat
tell application "Finder"
delete deleteThis
end tell
Alternatively, if you're able to store the file paths as HFS paths instead of POSIX paths, you can skip the coercion:
set deleteThis to paragraphs of (read "files.txt")
tell application "Finder"
delete deleteThis
end tell
tell application "Finder"
set file_list to entire contents of (choose folder with prompt "Please select directory.")
move file_list to trash
end tell

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

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