Using Applescript to transfer files from first Tab to second active Tab in finder

Hey Guys

I'm not good in applescript, and I tried to find solution in the internet but failed. So I come here to ask help.

Base on the image there are 2 folders opened in tabs in the finder Tab 1 folder is"Renaming" and Tab 2 folder is "Southwest Orange, FL"

The Applescript I need is to move all files from folder "Renaming" or Tab 1 to "Tab 2" which is now the "Sothwest Orange, FL" the Tab 2 is not permanent I will assign another folder in "Tab 2". So please ignore folder name in the second active tab.

Please help me guys. Thank you in advance

If the tabs were, instead, separate windows, this would be a much easier job, as, unfortunately—at least in High Sierra, and I doubt it to have changed for the better in Mojave—one can only reference the first tab in any one group of tabs in a Finder window using AppleScript.

Ideally, what you want instead is the path to the folder of the second tab, "SouthWest Orange, FL", but I'm guessing from the nature of the question, that this second folder (and indeed the first) could be any arbitrary folder(s) ?

Without access to this additional information, the other way to achieve it is through UI scripting. It's less robust unless it operates under known conditions. I typically dislike UI scripting, but it seems appropriate in this case and it's a reasonably clean implementation:

tell application "Finder"
	if not (exists front Finder window) then return -- No Finder windows
	
	set fs to my contentsOfFinderWindowAtTabIndex:1
	set gs to my contentsOfFinderWindowAtTabIndex:2
	
	if false is in [fs, gs] then return -- Only one tab open
	
	if gs = {} then
		set [fs, gs] to [gs, fs]
		my switchToTabWithIndex:2
	else
		my switchToTabWithIndex:1
	end if
	
	move gs to (get the front Finder window's target)
end tell



on contentsOfFinderWindowAtTabIndex:(i as integer)
	local i
	
	tell application "Finder" to tell the front Finder window
		set t to its name
		my switchToTabWithIndex:i
		if the result = false then return false
		set fs to every file in it as alias list
		my switchToTabWithTitle:t
	end tell
	
	fs
end contentsOfFinderWindowAtTabIndex:

to switchToTabWithIndex:(i as integer)
	tell application "System Events" to tell ¬
		process "Finder" to tell ¬
		window 1 to tell ¬
		tab group 1 to tell ¬
		radio buttons
		
		try
			click item i
		on error
			false
		end try
	end tell
end switchToTabWithIndex:

to switchToTabWithTitle:(t as string)
	tell application "System Events" to tell ¬
		process "Finder" to tell ¬
		window 1 to tell ¬
		tab group 1 to tell ¬
		(a reference to radio buttons)
		
		click item 1 of (it whose title = t)
	end tell
end switchToTabWithTitle:

There are a couple of caveats, relating to the robustness of this script:

  • Currently, it will only operate on the first two open tabs of the front finder window. If you have a third tab open, even if selected, it will be ignored.

  • The script assumes you wish to transfers the files from one tab to the other tab, and it will operate predictably and reliably if one of these tabs is empty, in which case the files are moved from the tab containing files to the empty tab, regardless of which tab is selected.

  • If neither tab is empty, then the files are moved from the second tab to the first tab, regardless of which tab is selected (the first tab being the leftmost tab).

It is possible to improve the script so it doesn't have to operate under such stringent caveats, but it would require making the script longer and I don't currently have the time to invest in doing that just now when I suspect (and hope) this script might suffice.

If you do later decide you have a set up that allows the folder paths of each tab to be easily accessed, then let us know and someone can draft a more suitable script. Such a set up would include the situation where both folders are subfolders in the same directory (i.e. both have the same parent folder), in which case retrieving the parent of one gives us the parent for the other, and together with the names of both tabs (which we can get with a tiny amount of UI script), gets us the path to both folders.


Note: Because this script uses UI scripting, you may be prompted to grant accessibility privileges to the app executing the script, and to System Events. This is safe to do so, and required for the script to execute properly.

1 Like

As a matter of fact things are different in Mojave, though I wouldn't say better. AppleScript now recognizes tabs as separate Finder windows, but it still doesn't have an explicit tab object as distinct from a window.

Below is a script I've been using for a few years that allows the user to choose from a list of open windows if there are more than two. One thing I never got around to was comparing the full path of the window targets rather than just their names, so it gets confused if there are two windows open to different folders with the same name.

tell application "Finder"
set filelist to selection as list
if (count filelist) < 1 then return
set fw to name of container of item 1 of filelist
set ow to name of windows
set aw to {}
repeat with anItem in ow
	set t to anItem as text
	if t is not fw then copy t to end of aw
end repeat
set c to count aw
if c = 0 then
	set dw to the desktop
	display dialog ("Move " & ((item 1 of filelist) as text) & " to the Desktop?")
	move filelist to dw
	return
else if c = 1 then
	set dw to (aw as text)
	display dialog ("Move " & ((item 1 of filelist) as text) & " to " & dw & "?")
else
	set dw to (choose from list aw with prompt "Move items to:" without multiple selections allowed) as text
end if
set dest to target of window dw
move filelist to dest

end tell

1 Like

Hi, Thank you for your effort in writing this code. But still I cant use it.
The Objective I want is:

The "Renaming" folder in Tab1 is where I stored the .txt files collected from KMaestro.
then transfer them in the Second folder in Tab2. But tab2 folder is not permanent, I will assign another folder in tab2 after collecting all the .txt files I need from "Renaming" Folder.

Maybe its easy also if we can make this into 2 windows and the "Renaming" Folder will always set into the main window in window1. And every time I run the script it will transfer all the data from "Renaming" folder in window 1 to window 2. Can you help me on that?

Thanks a lot.

Have you tried mine? Since your screenshot is in dark mode, I assume you're running Mojave, so unless there's something I'm misunderstanding, it should do the trick as long as the source folder is frontmost, the files you want to move are selected, and if you have more than two tabs/windows open they all have different names. (I originally wrote the script as part of an effort to replicate the functions of "Commander"-type dual-pane file managers.)

OK, so I got "tab1" and "tab2" the wrong way round. That's easily fixed: if "tab2" is empty, it makes no difference and the script will move the files in "Renaming" to the empty "tab2". If it's not empty, then you can either swap the positions of "tab1" and "tab2" physically; or identify the four lines (line numbers 4, 5, 11, and 13) in the script ending with ":1" or ":2", and swap "1" and "2" around.

However, @eurobubba has stated that the object hierarchy for Finder tabs/windows is different in Mojave. Since it doesn't have a tab object anymore, this actually makes my script useless. Sorry about that.

@eurobubba has provided a script that he says should do the job in Mojave.

Looking through your code, this is very easily fixed by using the id property of the windows instead of the name. You can also do away with the repeat loop by using a whose filter, which would also provide performance improvements:

set aw to the name of every Finder window where its name ≠ fw

I'd recommend using the Finder window object (assuming Mojave still has this) rather than the window object, in case there happen to be information panes or a preference window open.

I hope you don't mind that I went ahead and made a few modifications to your script along these lines. Hopefully, it saves you a job in the future, assuming this version works in Mojave.

Modified AppleScript
property text item delimiters : linefeed

tell application "Finder"
	set filelist to selection as alias list
	if {} = filelist then return
	
	set fw to the id of the front Finder window
	set aw to a reference to (every Finder window where its id ≠ fw)
	set dw to the desktop
	
	set c to count aw
	
	if c < 2 then
		if c = 1 then set [dw] to aw's target
		display dialog "Move " & item 1 of the filelist & " to " & dw's name & "?"
	else
		set wl to paragraphs of (aw's target as text)
		set [dw] to (choose from list wl with prompt "Move items to:" without multiple selections allowed)
	end if
	
	move the filelist to dw
end tell
1 Like

Nice — and thanks for turning me on to the square bracket notation, which I hadn't been familiar with. But on my system your code throws an error at the line

set wl to paragraphs of (aw as text)

which I've only been able to fix by adding another loop. The code below now works on my system (meanwhile I can't quite get the preformatted text notation in this forum to work right either, but the code should all be there):

property text item delimiters : linefeed

tell application "Finder"
set filelist to selection as alias list
if {} = filelist then return

set fw to the id of the front Finder window
set aw to the target of every Finder window where its id ≠ fw
set dw to the desktop

set c to count aw

if c < 2 then
	if c = 1 then set [dw] to aw
	display dialog "Move " & item 1 of the filelist & " to " & dw's name & "?"
else
	set awt to {}
	repeat with w in aw
		copy (w as text) to end of awt
	end repeat
	set wl to paragraphs of (awt as text)
	set [dw] to (choose from list wl with prompt "Move items to:" without multiple selections allowed)
end if

move the filelist to dw

end tell

Today's been a day where I've made clumsy mistakes, misread things, etc. etc. Here, I had two versions of the script I was editing in parallel, and I went and copied the one that didn't work into the forum post. D'oh! I've updated the script in my previous reply with the correct code, and I've literally just tested it to double-check that it works in High Sierra.

Thanks for reporting the error.

Cool, your updated script works here (and hey, no loop)!

I'm curious, what advantage do you see in using the square brackets?

In my testing, the script sets the dw variable to the same result, whether brackets are used, or not used:

--- Using Brackets [] ---
if c = 1 then set [dw] to aw's target

--- Does NOT Change the Results of Using NO Brackets ---
if c = 1 then set dw to aw's target

In both cases the result is a list.

According to AppleScript Lexical Conventions -- AppleScript Language Guide, curly braces "{ }" are used to denote both lists and records.

1 Like

I don't know that I'll ever use them, but it's always good to know an option exists. Apparently there are some subtle differences between the square and curly bracket versions of lists, according to the discussion here: https://lists.apple.com/archives/applescript-users/2009/Dec/msg00318.html

1 Like

That's right, [] remains from an earlier period (singly linked lists vs indexed arrays) and there are some subtle edges cases in which the two behave slightly differently.

They're easier to type than a curly brace, for one, not requiring the shift key to be depressed. But it's important to know that there are differences. Square brackets don't respect text item delimiters for one, which can be a very useful property.

They can also make reading a script a bit easier when using records. Although records themselves cannot use square bracket notation, lists contained within them can. So, to some,

{a:[1, 2, 3], b:[4, 5, 6], ...}

might be more palatable than

{a:{1, 2, 3}, b:{4, 5, 6}, ...}

when those records become very populated.

But, as is often best, just use what you're most comfortable using unless there's a good reason not to.

The results are most definitely different. In AppleScript, as you know, variables can be assigned by way of listing several declarations together:

set [a, b, c] to [1, 2, 3]

This sets a to 1, b to 2, and c to 3. If we had more variables than values, the script will throw an error (obviously). However, if we have fewer variables than values, the variables declared are filled, and the remaining values are discarded. Therefore:

set [a, b] to [1, 2, 3]

sets a to 1, and b to 2, whilst the value 3 goes unused. By extension:

set [a] to [1, 2, 3]

sets a to 1, and the 2 and 3 are unused. In other words:

set [dw] to aw's target

sets dw to the first item in the list aw's target. Whereas:

set dw to aw's target

copies the list aw's target to the variable dw. So with one you get a unary value, and with the other, you get a list.

I suspect you were just looking at the results pane to see what value was returned by that operation. However, you'd need to add the line return dw to see what value was actually assigned to dw, and not just the last value returned by the operation.

(However, there is no difference here between using square brackets vs. curly braces.)

2 Likes

(However, there is no difference here between using square brackets vs. curly braces.)

Almost no difference :slight_smile:

Try this:

on run
    
    -- Works,
    set end of {} to 3
    
    -- Fails ...
    set end of [] to 3
    
end run

or

on run
    
    set xs to {1, 2, 3}
    set ys to [1, 2, 3]
    
    try
        set end of xs to 7
        set end of ys to 7
    end try
    
    {xs, ys}
end run
1 Like

"no difference here", referring to the specific situation I was discussing in that reply. I'm generally aware of the differences between indexed arrays and linked lists.

2 Likes

According to that post by Shane Stanley, there are some differences.
It should be noted that use of square brackets has been deprecated, and that curly braces is much faster.

As we all know, a deprecated feature is subject to being dropped/removed at any time, so I for one would not want to use a feature like square brackets, especially since it use with lists is slower than curly braces.

From Above Link

Well, this is a case where =="regular" lists (vectors) are (now) much faster
than linked lists==, at least OMM (OS 10.5.8). So I guess you mean that this
indicates that linked lists are still different from regular {} lists in
some way.

Yep.

As I said earlier, I thought that there had once
been some context where was faster, not slower, than {}. Whatever it
was may well no longer be the case - presumably there have been
optimizations to the current language - {} - ==which deprecated elements - == - might not have benefited from.

Yep.

In ==AppleScript 1.1, lists are represented as vectors.== This means that elements are stored in consecutive locations in memory rather than linked together. ==This makes accessing elements by index fast== (constant time -- it doesn't matter about the value of the index), but makes concatenation generate much more garbage, as both halves of the concatenate operator (&) must be copied.

Although this does constitute a change in the default behavior from
AppleScript 1.0 to 1.1, ==we believe the new behavior is more intuitive==, and the old behavior can be preserved using the square bracket syntax.

The above link is from 2009, when AppleScript was in Version 1.1.
That is ancient history, as we are now at AppleScript 2.5+, as of macOS El Capitan.

Since square brackets were deprecated with AppleScript 1.1, I see no reason to use them now, and in fact, I have not seen them used elsewhere.

I stand corrected. They are different.

The problem is that square brackets are deprecated, and their use/behavior is NOT documented in the AppleScript Language Guide.

If you want to take the risk of mixing behavior between square brackets and curly braces in scripts for your own use, that is your business. I would not want to share scripts that use square brackets with others, who have no easy way of understanding their behavior, and might wake up one day to a broken script.

So why do you use info for in many of your scripts that you share online ? And of all the reasons that AppleScript scripts are breaking nowadays, and in the likely future, square brackets is going to be way down at the very bottom of that list, probably behind info for. I think you're splitting hairs here.

Do you work for Apple? Or have Apple inside info? If not, then how would you know that Apple's priorities are?

Do as you wish. My only point is to alert users who are using scripts from others that use square brackets, which were deprecated in 2009, and don't offer any real benefits. High risk, low return.

Whatever. I'm done.

Hey Guys,

The one thing I'm particularly unhappy about with the two list formats is that after the fact you can't tell which is which.

Both have a class of list.

So you have to be sure to make it obvious in the variable name what kind of list you're using, or it'll eventually come back to bite you.

-Chris