Move files to the correct subfolders

I'm looking for a script, macro or tool that can help me to move (exported) files back to the correct subfolders.

My (translation) editor can import all files from a folder containing subfolders:

Job123\Parts
Job123\Documentation
Job123\Rest

The subfolder Parts will e.g. contain:

abc.xlsx
def.xlsx
ghi.xlsx

The editor will export all (xlsx and xlsm) files to ONE folder on my Desktop: ~\Desktop\Export

The correct subfolder names could be derived from ~\Desktop\Import

The names and path of the import and export folders can always be the same. The names of the subfolders and files within them will vary.

Perhaps someone has a bit of code that I can work on?

Thanks in advance!

Hans

I'm sure this is doable, but we need some clear, real-world data.
Please show in Code Blocks real-world data for:

  1. Source folders, subfolders, and files, all clearly labeled.
  2. The desired output of the same.

IOW, a complete before and after set of data.

These are the files that are imported:

/Users/hl/Desktop/Import/STL-1/a1.xlsx
/Users/hl/Desktop/Import/STL-1/a10.xlsx
/Users/hl/Desktop/Import/STL-1/a11.xlsx
/Users/hl/Desktop/Import/STL-1/a12.xlsx
/Users/hl/Desktop/Import/STL-1/a13.xlsx
/Users/hl/Desktop/Import/STL-1/a14.xlsx
/Users/hl/Desktop/Import/STL-1/a2.xlsx
/Users/hl/Desktop/Import/STL-1/a3.xlsx
/Users/hl/Desktop/Import/STL-1/a4.xlsx
/Users/hl/Desktop/Import/STL-1/a5.xlsx
/Users/hl/Desktop/Import/STL-1/a6.xlsx
/Users/hl/Desktop/Import/STL-1/a7.xlsx
/Users/hl/Desktop/Import/STL-1/a8.xlsx
/Users/hl/Desktop/Import/STL-1/a9.xlsx
/Users/hl/Desktop/Import/STL-2/b1.xlsx
/Users/hl/Desktop/Import/STL-2/b2.xlsx
/Users/hl/Desktop/Import/STL-2/b3.xlsx
/Users/hl/Desktop/Import/STL-2/b4.xlsx
/Users/hl/Desktop/Import/STL-2/b5.xlsx
/Users/hl/Desktop/Import/STL-2/b6.xlsx
/Users/hl/Desktop/Import/STL-2/b7.xlsx
/Users/hl/Desktop/Import/STL-3/c1.xlsx
/Users/hl/Desktop/Import/STL-3/c10.xlsx
/Users/hl/Desktop/Import/STL-3/c11.xlsx
/Users/hl/Desktop/Import/STL-3/c12.xlsx
/Users/hl/Desktop/Import/STL-3/c13.xlsx
/Users/hl/Desktop/Import/STL-3/c2.xlsx
/Users/hl/Desktop/Import/STL-3/c3.xlsx
/Users/hl/Desktop/Import/STL-3/c4.xlsx
/Users/hl/Desktop/Import/STL-3/c5.xlsx
/Users/hl/Desktop/Import/STL-3/c6.xlsx
/Users/hl/Desktop/Import/STL-3/c7.xlsx
/Users/hl/Desktop/Import/STL-3/c8.xlsx
/Users/hl/Desktop/Import/STL-3/c9.xlsx
/Users/hl/Desktop/Import/STL-4/d1.xlsm
/Users/hl/Desktop/Import/STL-4/d2.xlsm
/Users/hl/Desktop/Import/STL-4/d3.xlsm
/Users/hl/Desktop/Import/STL-4/d4.xlsm
/Users/hl/Desktop/Import/STL-4/d5.xlsm
/Users/hl/Desktop/Import/STL/0101.xlsx
/Users/hl/Desktop/Import/STL/0202.xlsx
/Users/hl/Desktop/Import/STL/0303.xlsx
/Users/hl/Desktop/Import/STL/0404.xlsx
/Users/hl/Desktop/Import/STL/0505.xlsx
/Users/hl/Desktop/Import/STL/0606.xlsx
/Users/hl/Desktop/Import/STL/0707.xlsx
/Users/hl/Desktop/Import/STL/0808.xlsx
/Users/hl/Desktop/Import/STL/0909.xlsx
/Users/hl/Desktop/Import/STL/1010.xlsx
/Users/hl/Desktop/Import/STL/1111.xlsx
/Users/hl/Desktop/Import/STL/1212.xlsx
/Users/hl/Desktop/Import/STL/1313.xlsx
/Users/hl/Desktop/Import/STL/1414.xlsx
/Users/hl/Desktop/Import/STL/1515.xlsx
/Users/hl/Desktop/Import/STL/1616.xlsx
/Users/hl/Desktop/Import/STL/1717.xlsx
/Users/hl/Desktop/Import/STL/1818.xlsx
/Users/hl/Desktop/Import/STL/1919.xlsx
/Users/hl/Desktop/Import/STL/2020.xlsx
/Users/hl/Desktop/Import/STL/2121.xlsx
/Users/hl/Desktop/Import/STL/2222.xlsx
/Users/hl/Desktop/Import/STL/2323.xlsx
/Users/hl/Desktop/Import/STL/2424.xlsx
/Users/hl/Desktop/Import/STL/2525.xlsx
/Users/hl/Desktop/Import/STL/2626.xlsx
/Users/hl/Desktop/Import/STL/2727.xlsx
/Users/hl/Desktop/Import/STL/2828.xlsx
/Users/hl/Desktop/Import/STL/2929.xlsx
/Users/hl/Desktop/Import/STL/3030.xlsx
/Users/hl/Desktop/Import/STL/3131.xlsx
/Users/hl/Desktop/Import/STL/3232.xlsx
/Users/hl/Desktop/Import/STL/3333.xlsx
/Users/hl/Desktop/Import/STL/3434.xlsx
/Users/hl/Desktop/Import/STL/3535.xlsx
/Users/hl/Desktop/Import/STL/3636.xlsx
/Users/hl/Desktop/Import/STL/3737.xlsx
/Users/hl/Desktop/Import/STL/3838.xlsx
/Users/hl/Desktop/Import/STL/3939.xlsx
/Users/hl/Desktop/Import/STL/4040.xlsx
/Users/hl/Desktop/Import/STL/4141.xlsx
/Users/hl/Desktop/Import/STL/4242.xlsx
/Users/hl/Desktop/Import/STL/4343.xlsx
/Users/hl/Desktop/Import/STL/4444.xlsx
/Users/hl/Desktop/Import/STL/4545.xlsx
/Users/hl/Desktop/Import/STL/4646.xlsx

And here's the export:

/Users/hl/Desktop/Export/d1.xlsm
/Users/hl/Desktop/Export/d2.xlsm
/Users/hl/Desktop/Export/d3.xlsm
/Users/hl/Desktop/Export/d4.xlsm
/Users/hl/Desktop/Export/d5.xlsm
/Users/hl/Desktop/Export/b7.xlsx
/Users/hl/Desktop/Export/b6.xlsx
/Users/hl/Desktop/Export/b5.xlsx
/Users/hl/Desktop/Export/b4.xlsx
/Users/hl/Desktop/Export/b3.xlsx
/Users/hl/Desktop/Export/b2.xlsx
/Users/hl/Desktop/Export/b1.xlsx
/Users/hl/Desktop/Export/a14.xlsx
/Users/hl/Desktop/Export/a13.xlsx
/Users/hl/Desktop/Export/a12.xlsx
/Users/hl/Desktop/Export/a11.xlsx
/Users/hl/Desktop/Export/a10.xlsx
/Users/hl/Desktop/Export/a9.xlsx
/Users/hl/Desktop/Export/a8.xlsx
/Users/hl/Desktop/Export/a7.xlsx
/Users/hl/Desktop/Export/a6.xlsx
/Users/hl/Desktop/Export/a5.xlsx
/Users/hl/Desktop/Export/a4.xlsx
/Users/hl/Desktop/Export/a3.xlsx
/Users/hl/Desktop/Export/a2.xlsx
/Users/hl/Desktop/Export/a1.xlsx
/Users/hl/Desktop/Export/c13.xlsx
/Users/hl/Desktop/Export/c12.xlsx
/Users/hl/Desktop/Export/c9.xlsx
/Users/hl/Desktop/Export/c8.xlsx
/Users/hl/Desktop/Export/c7.xlsx
/Users/hl/Desktop/Export/c5.xlsx
/Users/hl/Desktop/Export/c4.xlsx
/Users/hl/Desktop/Export/c2.xlsx
/Users/hl/Desktop/Export/c1.xlsx
/Users/hl/Desktop/Export/c11.xlsx
/Users/hl/Desktop/Export/c10.xlsx
/Users/hl/Desktop/Export/c6.xlsx
/Users/hl/Desktop/Export/c3.xlsx
/Users/hl/Desktop/Export/4545.xlsx
/Users/hl/Desktop/Export/2828.xlsx
/Users/hl/Desktop/Export/2323.xlsx
/Users/hl/Desktop/Export/1212.xlsx
/Users/hl/Desktop/Export/0606.xlsx
/Users/hl/Desktop/Export/0404.xlsx
/Users/hl/Desktop/Export/0303.xlsx
/Users/hl/Desktop/Export/0101.xlsx
/Users/hl/Desktop/Export/4646.xlsx
/Users/hl/Desktop/Export/4444.xlsx
/Users/hl/Desktop/Export/4343.xlsx
/Users/hl/Desktop/Export/4242.xlsx
/Users/hl/Desktop/Export/4141.xlsx
/Users/hl/Desktop/Export/4040.xlsx
/Users/hl/Desktop/Export/3939.xlsx
/Users/hl/Desktop/Export/3838.xlsx
/Users/hl/Desktop/Export/3737.xlsx
/Users/hl/Desktop/Export/3636.xlsx
/Users/hl/Desktop/Export/3535.xlsx
/Users/hl/Desktop/Export/3434.xlsx
/Users/hl/Desktop/Export/3333.xlsx
/Users/hl/Desktop/Export/3232.xlsx
/Users/hl/Desktop/Export/3131.xlsx
/Users/hl/Desktop/Export/3030.xlsx
/Users/hl/Desktop/Export/2929.xlsx
/Users/hl/Desktop/Export/2727.xlsx
/Users/hl/Desktop/Export/2626.xlsx
/Users/hl/Desktop/Export/2525.xlsx
/Users/hl/Desktop/Export/2424.xlsx
/Users/hl/Desktop/Export/2222.xlsx
/Users/hl/Desktop/Export/2121.xlsx
/Users/hl/Desktop/Export/2020.xlsx
/Users/hl/Desktop/Export/1919.xlsx
/Users/hl/Desktop/Export/1818.xlsx
/Users/hl/Desktop/Export/1717.xlsx
/Users/hl/Desktop/Export/1616.xlsx
/Users/hl/Desktop/Export/1515.xlsx
/Users/hl/Desktop/Export/1414.xlsx
/Users/hl/Desktop/Export/1313.xlsx
/Users/hl/Desktop/Export/1111.xlsx
/Users/hl/Desktop/Export/1010.xlsx
/Users/hl/Desktop/Export/0909.xlsx
/Users/hl/Desktop/Export/0808.xlsx
/Users/hl/Desktop/Export/0707.xlsx
/Users/hl/Desktop/Export/0505.xlsx
/Users/hl/Desktop/Export/0202.xlsx

There won't be any duplicate file names.

This is the desired result:

(Files from the Export folder are moved to subfolders corresponding to those under the Import folder.)

/Users/hl/Desktop/Export/STL-1/a1.xlsx
/Users/hl/Desktop/Export/STL-1/a10.xlsx
/Users/hl/Desktop/Export/STL-1/a11.xlsx
/Users/hl/Desktop/Export/STL-1/a12.xlsx
/Users/hl/Desktop/Export/STL-1/a13.xlsx
/Users/hl/Desktop/Export/STL-1/a14.xlsx
/Users/hl/Desktop/Export/STL-1/a2.xlsx
/Users/hl/Desktop/Export/STL-1/a3.xlsx
/Users/hl/Desktop/Export/STL-1/a4.xlsx
/Users/hl/Desktop/Export/STL-1/a5.xlsx
/Users/hl/Desktop/Export/STL-1/a6.xlsx
/Users/hl/Desktop/Export/STL-1/a7.xlsx
/Users/hl/Desktop/Export/STL-1/a8.xlsx
/Users/hl/Desktop/Export/STL-1/a9.xlsx
/Users/hl/Desktop/Export/STL-2/b1.xlsx
/Users/hl/Desktop/Export/STL-2/b2.xlsx
/Users/hl/Desktop/Export/STL-2/b3.xlsx
/Users/hl/Desktop/Export/STL-2/b4.xlsx
/Users/hl/Desktop/Export/STL-2/b5.xlsx
/Users/hl/Desktop/Export/STL-2/b6.xlsx
/Users/hl/Desktop/Export/STL-2/b7.xlsx
/Users/hl/Desktop/Export/STL-3/c1.xlsx
/Users/hl/Desktop/Export/STL-3/c10.xlsx
/Users/hl/Desktop/Export/STL-3/c11.xlsx
/Users/hl/Desktop/Export/STL-3/c12.xlsx
/Users/hl/Desktop/Export/STL-3/c13.xlsx
/Users/hl/Desktop/Export/STL-3/c2.xlsx
/Users/hl/Desktop/Export/STL-3/c3.xlsx
/Users/hl/Desktop/Export/STL-3/c4.xlsx
/Users/hl/Desktop/Export/STL-3/c5.xlsx
/Users/hl/Desktop/Export/STL-3/c6.xlsx
/Users/hl/Desktop/Export/STL-3/c7.xlsx
/Users/hl/Desktop/Export/STL-3/c8.xlsx
/Users/hl/Desktop/Export/STL-3/c9.xlsx
/Users/hl/Desktop/Export/STL-4/d1.xlsm
/Users/hl/Desktop/Export/STL-4/d2.xlsm
/Users/hl/Desktop/Export/STL-4/d3.xlsm
/Users/hl/Desktop/Export/STL-4/d4.xlsm
/Users/hl/Desktop/Export/STL-4/d5.xlsm
/Users/hl/Desktop/Export/STL/0101.xlsx
/Users/hl/Desktop/Export/STL/0202.xlsx
/Users/hl/Desktop/Export/STL/0303.xlsx
/Users/hl/Desktop/Export/STL/0404.xlsx
/Users/hl/Desktop/Export/STL/0505.xlsx
/Users/hl/Desktop/Export/STL/0606.xlsx
/Users/hl/Desktop/Export/STL/0707.xlsx
/Users/hl/Desktop/Export/STL/0808.xlsx
/Users/hl/Desktop/Export/STL/0909.xlsx
/Users/hl/Desktop/Export/STL/1010.xlsx
/Users/hl/Desktop/Export/STL/1111.xlsx
/Users/hl/Desktop/Export/STL/1212.xlsx
/Users/hl/Desktop/Export/STL/1313.xlsx
/Users/hl/Desktop/Export/STL/1414.xlsx
/Users/hl/Desktop/Export/STL/1515.xlsx
/Users/hl/Desktop/Export/STL/1616.xlsx
/Users/hl/Desktop/Export/STL/1717.xlsx
/Users/hl/Desktop/Export/STL/1818.xlsx
/Users/hl/Desktop/Export/STL/1919.xlsx
/Users/hl/Desktop/Export/STL/2020.xlsx
/Users/hl/Desktop/Export/STL/2121.xlsx
/Users/hl/Desktop/Export/STL/2222.xlsx
/Users/hl/Desktop/Export/STL/2323.xlsx
/Users/hl/Desktop/Export/STL/2424.xlsx
/Users/hl/Desktop/Export/STL/2525.xlsx
/Users/hl/Desktop/Export/STL/2626.xlsx
/Users/hl/Desktop/Export/STL/2727.xlsx
/Users/hl/Desktop/Export/STL/2828.xlsx
/Users/hl/Desktop/Export/STL/2929.xlsx
/Users/hl/Desktop/Export/STL/3030.xlsx
/Users/hl/Desktop/Export/STL/3131.xlsx
/Users/hl/Desktop/Export/STL/3232.xlsx
/Users/hl/Desktop/Export/STL/3333.xlsx
/Users/hl/Desktop/Export/STL/3434.xlsx
/Users/hl/Desktop/Export/STL/3535.xlsx
/Users/hl/Desktop/Export/STL/3636.xlsx
/Users/hl/Desktop/Export/STL/3737.xlsx
/Users/hl/Desktop/Export/STL/3838.xlsx
/Users/hl/Desktop/Export/STL/3939.xlsx
/Users/hl/Desktop/Export/STL/4040.xlsx
/Users/hl/Desktop/Export/STL/4141.xlsx
/Users/hl/Desktop/Export/STL/4242.xlsx
/Users/hl/Desktop/Export/STL/4343.xlsx
/Users/hl/Desktop/Export/STL/4444.xlsx
/Users/hl/Desktop/Export/STL/4545.xlsx
/Users/hl/Desktop/Export/STL/4646.xlsx

OK, so if I understand correctly, you want to iterate through the files in ~/Desktop/Export, and then you see, for example d1.xlsm (are they always .xslm files?). So you look to see where d1.xlsm is in ~/Desktop/Import, and it will appear in exactly one location, in this case ~/Desktop/Import/STL-4/d1.xlsm, so you want to move/rename the file to ~/Desktop/Export/STL-4/d1.xlsm (creating the subdirectory STL-4 as needed).

And there are no files directly within ~/Desktop/Import (only directories)?

And no directories initially in ~/Desktop/Export (only files)?

And there is only one level of directories in ~/Desktop/Import?

With that clarity it should be fairly straight forward to write the macro/script.

Correct, and: The folders can also contain XLSX and DOCX files.

Correct

Indeed

Yes

Before starting, ensure you have your Mac fully backed up. Any time you are going to automate moving files around or anything like that, you need to contemplate the consequences of your macro being incorrect and you moving all the wrong files to all the wrong places. So complete backups are absolutely essential.

So to accomplish this task (or any task really) you break it in to component parts.

Iterate through the contents of the folder. Use the For Each action with the Folder Contents collection.

For each of those, you may want to use an If Then Else action with a Variable condition to ensure the path ends is .xlsm or .xlsx or .docx depending on your desires so you only process files you expect to find.

Use the Split Path action to extract just the filename.

Now you have the trickiest part, how to find the location of the matching file in the Import directory. Probably the easiest way to do that is to use the unix find shell command.

find ~/Desktop/Import -name "$KMVar_FileName"

That will return the path to the matching file - save it in a variable. Now you have the original path.

Use the Split Path action to get the parent path (you know the name already), and then again to get the name of the directory.

Now create the directory with the New Folder action (and configure it to ignore and not report errors in creating the directory if it has already been created): New Folder ~/Export/%Variable%ParentFolder%.

And finally you can move the file with the More or Rename File action. Move %Variable%Path% to ~/Export/%Variable%ParentFolder%.

And that should pretty much do the trick.

You can implement each part as you go, using the Log action to record what is happening or what you'll do next in the Engine.log file.

1 Like

Thanks for your help!

First, I want to have all names of all files in the Export folder displayed.

What am I doing wrong here?

@ALYB, to be safe, you should include a -maxdepth 1 parameter to limit the find to just that folder.

find ~/Desktop/Import -maxdepth 1 -name "$KMVar_FileName"

I don't see anything obviously wrong with your Actions.
What exactly is the result when you run the Macro?
Of course, make sure there are actually some file in the folder.

As an alternate, you could use this to list all files in the folder:
find ~/Desktop/Export -maxdepth 1 -type f

image

1 Like

Your macro looks fine, are you sure you have files in ~/Desktop/Export?

Make sure there are no spaces or invisible characters or such in the path - possibly select the folder using the folder button on the right.

Check the value of the File variable in the Keyboard Maestro Variables preferences after the macro execution and verify it is the expected path.

1 Like

Strangely enough, the next day (after the MacBook Pro had a good sleep) the macro worked. So I continued. This is the result:


Move Exported Files to Correct Folder.kmmacros (5.4 KB)

I guess that when doing everything right, I'd have to removed the matched line from the variable AllImportFileNames every time? This would speed things up when you have many folders and files.

Never bother trying to improve the speed of a macro until you are annoyed by the speed of a macro. Otherwise, use the simplest macro you can possibly make and let the fantastically fast CPU do its work.

If you have large numbers of files in the import directory, then yes, this might start to get slow. There are solutions to that, but removing the matching lines is probably not one of them - that would only half the time. Instead, you would pre-populate a dictionary and use that instead and that would be much faster in the case where there are large numbers of entries. But definitely don't bother until you actually need to - it probably will be fast enough as is.

2 Likes

Peter, my feelings exactly.
Corollary: Don't let the little things annoy you. :wink:

Corollary: They are all little things.

I want to make the macro more flexible by allowing to run it on the selected folder on the Desktop (with a name that can contain spaces and umlauts). I'm having difficulties to have the Path passed correctly to the shell script:

Hey Hans,

Please provide an example of a path you're having problems with.

-Chris

Hello Chris,

Thank you for getting back on this.

The path:

The macro:

I'll attach the macro and a ZIP file that you could extract to your Desktop, for testing.

Thanks!

Hans

TestOnFolder.kmmacros (3.7 KB)
Hähner Doku 2018-05-21.zip (196.1 KB)

Hey Hans,

You bet.

Thanks. That made finding the problem simple.

You've mis-cased part of the KMVAR prefix for shell variables in the find command.

Easy to do.

Hard to see.

When shell scripts fail in Keyboard Maestro you should always make sure they work properly outside of Keyboard Maestro (when possible).

Especially when you're passing variables around and messing with quoted (or escaped) path strings.

The place to start is to pull the fully assembled shell script out of Keyboard Maestro and into a good programming/text editor like BBEdit – examine the syntax – and see if it works.

Here's how I did that with your code:

I turned off everything inside the For Each action except this:

image

** Note that I changed your variable name to pathStr. (I vehemently dislike using Path as a variable name.)

Other than the variable name change the find script is verbatim from your macro.

Using cat with a here document in this way lets me expand all the variables and other elements of the shell script without executing it – and I don't have to change any of the quoting to get it to work.

The result was:

find "" -iname "*.xls"

That's pretty clearly a variable problem, so I looked a third time a $KMVar_pathStr and finally realized a couple of letters were the wrong case.

Once I fixed the case issue your macro worked fine.

And it took me longer to write this up than it did to debug the problem.  :sunglasses:

-Chris

1 Like

Thank you, Chris.

I too finally realised that it had to be $KMVAR_pathStr

When I looked at https://wiki.keyboardmaestro.com/action/Execute_a_Shell_Script I didn't realise that the KMVAR part has to be written exactly like that.

(BTW: I did test the script directly in Terminal, but I didn't get any feedback that helped me.)

I've updated my macro to this:

The new version of the macro (I've changed the name), can be found here:

Move Exported Files to Selected Folder.kmmacros (6.6 KB)