Iterating through file line by line in AppleScript? - applescript

I am trying to figure out how to iterate through a file line by line in AppleScript. Similar to a bash script like so:
for LINE in $(cat file)
do
echo ${LINE}
done
Any tips? Thanks!

I can't take credit for writing this, I lifted the code from a response to a post in the MacRumors forums.
tell application "Finder"
set Names to paragraphs of (read (choose file with prompt "Pick text file containing track names"))
repeat with nextLine in Names
if length of nextLine is greater than 0 then
--Do something with the next name, which is stored in "nextLine"
end if
end repeat
end tell
Original code credit to HexMonkey on the MacRumors forum.

Related

Remove specific characters from highlighted text using AppleScript or Automator

I have a question and maybe someone can point me in the right direction.
I would like to be able to copy Text (mostly from "Get Info") and replace all the “.” with a space excluding the “.”before the file extension using AppleScript or Automator. I'd like to use this service when i right click and select the script or automator service.
E.G
Contraband.2012.DVDRip.htif-NYsIC.avi
will turn to
Contraband 2012 DVDRip htif-NYsIC.avi
I've search everywhere on this site and various places but I just cant seem to find what i need. I don’t know where to start writing this script. Is what i described even possible in apple script? I just need to be pointed in the right direction and I'll try and figure the rest out I'm just at a loss right now.
Thank's in advance.
You could use a Run Shell Script action like this:
for f; do
base=${f##*/}
[[ $base =~ .+\..+ ]] || continue
noext=${base%.*}
mv "$f" "${f%/*}/${noext//./ }.${base##*.}"
done
Set "Pass input" to "as arguments". ${f##*/} removes the longest */ pattern from the start of f and ${f%/*} removes the shortest /* pattern from the end of f.
You could also use a Run AppleScript action like this:
on run {input}
repeat with f in input
set text item delimiters to "."
tell application "Finder"
set ti to text items of (get name of (f as alias))
if number of ti > 2 then
set AppleScript's text item delimiters to " "
set name of (f as alias) to (items 1 thru -2 of ti as text) & "." & item -1 of ti
end if
end tell
end repeat
end run

How to copy every line of text on a text file with Automator on OSX?

The deal is this:
I use http://www.clipmenu.com/ ClipMenu to have 20 states of the clipboard, because i need to copy each line of some txt file separated. So i open the txt file, and i go through every line hitting command+shift+→ then command+c then ↑ and so on until i reach the top and i have all the lines copied and stored in the history of ClipMenu.
My question is, is there a way to make a service or script that copies every single line in an automated way? i think i could make a script that repeat those keystrokes until it reaches the top of the txt file but i have no idea how to make it so.
Thanks a lot.
I do not know how to do this using Automator, but using mono [MonoMac] it is very simple:
using (System.IO.FileStream file = new System.IO.FileStream("path", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read)) {
using (System.IO.StreamReader reader = new System.IO.StreamReader(file)) {
while (!reader.EndOfStream) {
String line = reader.ReadLine ();
System.Windows.Forms.Clipboard.SetText(line);
}
}
}
Try:
set fileText to read (choose file) as «class utf8»
set filePara to paragraphs of fileText
repeat with aPara in filePara
set aPara to contents of aPara
if aPara ≠ "" then set the clipboard to aPara
end repeat
ClipMenu seems to ignore "transient" clipboards, so you also need a delay between the copy actions:
read POSIX file "/Users/username/Documents/test.txt" as «class utf8»
repeat with p in reverse of paragraphs of result
if contents of p is not "" then set the clipboard to contents of p
delay 1
end repeat
Or using UI scripting:
delay 1
tell application "TextEdit"
activate
set n to number of paragraphs of document 1
end tell
tell application "System Events"
key code {125, 123} using command down
repeat n times
key code 124 using {shift down, command down}
keystroke "c" using command down
key code 126
delay 1
end repeat
end tell
The key codes are listed in Events.h.

Print to stdout from osascript/Applescript

I have some AppleScript code that I'm executing with osascript. This is part of a larger Perl program. I'd like to be able to print to stdout from the AppleScript, then have the Perl script process the output. But I haven't been able to print from within AppleScript. What should I do?
Here's what I've tried:
do shell script "echo Foo". Does not ouptut Foo.
This Google Groups discussion does some trickery to open /dev/fd/1. For me, I get an error of "File Macintosh HD:dev:fd:1 wasn't found"
Here's the script I'm running:
tell application "Safari"
set window_list to every window
repeat with the_window in window_list
set tab_list to every tab in the_window
repeat with the_tab in tab_list
set the_url to the URL of the_tab
-- I'd like to put a print statement here,
-- instead of display dialog
display dialog the_url
end repeat
end repeat
end tell
Since osascript will automatically print the last value of a program, I could collect the URLs into a list and print that. But then my Perl script would have to parse the list, remove quotes, etc. It seems like it should be more straightforward to just print one URL per line.
Thanks
I don't know how to do what you're asking and I don't know Perl, however I think you could make the parsing from perl simple if you collect your urls in a string instead of a list. Each url would be on a separate line of the string. Perl should be able to turn that into an array pretty easily and then do something with it. Something like the below applescript. Of course you can use a different separator in the applescript. I used "return" but it could just as easily be a "comma" or any other character you want. Whatever is easiest for you in perl to change the string to an array.
set urlString to ""
tell application "Safari"
set window_list to every window
repeat with the_window in window_list
set tab_list to every tab in the_window
repeat with the_tab in tab_list
set the_url to the URL of the_tab
set urlString to urlString & the_url & return
end repeat
end repeat
end tell
return text 1 thru -2 of urlString
I found that I can use 'log' to dump results to STDERR,
though I had to use Chrome instead of Safari:
#!/usr/bin/osascript
tell application "Chrome"
repeat with w in every window
repeat with t in tabs of w
log (get URL of t)
end repeat
end repeat
end tell
Just use log is OK.
MacBookPro:~ zxj5470$ cat demo.scpt
tell application "Terminal"
set WindowNum to get window count
log WindowNum
end tell
MacBookPro:~ zxj5470$ osascript demo.scpt
1

Set list to shell script output in AppleScript

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

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