Automatically open a file with periodically changing filename

Yes and I'm so thankful for all of you. You gave me a lot of great ideas I wasn't even thinking about.
I'll try to answer all questions.

This is my work folder:
'/Users/xxxxx/Library/Mobile Documents/com~apple~CloudDocs/DaZ'

In there is all the stuff I need on a daily basis. My daily plan, my weekly plan, my list of students, attention list, homework list, list for emergencies, list of other teachers I work with or I have to give information to, important recent files with laws and stuff I use as reference.

One of those files I change on a weekly basis automatically with Hazel. Hazel makes a copy of the file, renames the copy with the actual school week and archives the old one into my Johnny Decimal folder system.
These are the rules:

I'm using an easy naming pattern. On the Sunday before the first week I create the first file. Hazel will rename it on a Sunday later with "Tagesplan SW 1+1"

So there always is only one file with "Tagesplan SW X" in the folder. I'm looking for a rule that looks for a file in that specific folder that begins with "Tagesplan" and opens it by Macro.

Yes, it is always the same folder.

No it is the only file with Tagesplan in its name.

Ok. I try to be more specific. I open my Macbook Air,
I open Finder if it isn't open yet,
I choose my work folder in Finder, it's the folder '/Users/xxxxx/Library/Mobile Documents/com~apple~CloudDocs/DaZ',
I look for the only file in the folder with "Tagesplan" in its name.
I doubleclick it to open it in Numbers.

Yes. It is the only one with Tagesplan in it, the other files are put into Archive every Sunday by Hazel.

No.

No.

No. I have some other files and folders in it. But just one with Tagesplan in its name.

Yes, you're right, it shouldn't matter. I bought Hazel in 2011 or so? And I'm having a ton of rules. Much later, in 2020 I bought KM and I decided to let Hazel do the file stuff and KM everything else. If I start to mix this up I'm afraid this will end in chaos.

It's just one. I figured out how to open files that use the same filename. KM has an "open file" action.
I thought it would be easier and KM has some action that says "open filename" and I could define it with placeholders, like open file with filename "Tagesplan*". But that's not possible I guess.

Okay. Here you go. Download this Example Macro by clicking on the link, then double-click the downloaded file to open in it Keyboard Maestro. Change the path to your actual path.

Open the Tagesplan File.kmmacros (4.0 KB)

To try and explain what is going on -

The For Each Loop is saying -

  1. Step through a folder one item at a time
  2. For each of those items, save its info to a Variable called "Local_File"
  3. Then check this info to see if it contains the text "Tagesplan"
    (The whole info saved would be the whole path "/Username/Desktop/Test Folder/Tagesplan.numbers")
  4. If the info matches this rule, open that path in Numbers
    And if the info matches break from the loop (as no need to check anything more)
  5. If the info does not match the rule, don't do anything (in which case the loop continues with checking the next item)
  6. If no matches are found the loop will complete and the Macro will end i.e. it will only run through the items once

The For Each loop is very powerful but I think not very intuitive. One of the things that confused me when I first tried to use it, is that it references Variables by name and in some of the fields those variable are referenced directly Local_File and in other field they are referred to as %Variable%Local_File%. This is because Keyboard Maestro has different types of fields - some accept Variables and Calculations directly but other fields are text fields and need the Variables to be quoted with the %s.

One way I like to build a Macro like this is to display what the Variables contain. This helps to understand what is going on. So, I might make a kind of test macro like this:

2 Likes

Awesome. Thank you! It works. Perfectly.
Just to understand this. For each "Local_File" defines that the variable "Local_File" stands for every item in the folder, right?
And then you do the conditions. This was the part I wasn't understanding. Now that I see it it looks so... logical. Thank you again!

1 Like

I have just edited my reply above to try and explain what is going on. Once you get your head around how this For Each Action works it opens up all sorts of possibilities.

1 Like

Many many thanks. And thank you for explaining every step. It not only works, I think I understand how it works. Awesome!

2 Likes

Then it's time to take it up a level :wink:

@Zabobon's excellent macro is where I'd usually stop, too. But suppose you decided to tweak your workflow and started archiving the old weekly files in a "Tagesplan" folder. Or wanted to to make some big edits to this week's file so saved an "Old-Tagesplan SW nn" copy, just in case.

Your folder might now look like

image

...and your "For Each" action will create a Collection of paths, alphabetically sorted, like

/path/to/MyFiles/Doc2.docx
/path/to/MyFiles/Old-Tagesplan SW 01.numbers
/path/to/MyFiles/Tagesplan
/path/to/MyFiles/Tagesplan SW 01.numbers
/path/to/MyFiles/What Does "Affects Case" Do?.kmmacros

...and work through them from top to bottom.

Because your matching against "if the path contains Tagesplan" you can see that the first match will be the wrong item.

But if you look at the paths above you'll see that the file you want can be precisely targeted by the path that includes the text /Tagesplan SW immediately followed by some digits (and only digits) which are immediately followed by the text .numbers -- and, for extra precision, all that occurs at the end of the line.

You don't know in advance what the digits will be. You could try and match every possible combination -- "Tagesplan SW 01.numbers" OR "Tagesplan SW 02.numbers" OR... "Tagesplan SW 99.numbers" -- but that'll get very annoying very quickly!

So you turn to a Regular Expression which, at its core, is "does this text match a defined pattern?". "RegEx" have their own "rules", and you can see a summary of their use, plus links to other resources, on the KM Wiki's Regular Expressions page.

For this, you only need to know that

  1. The "metacharacter" \s matches a white space character. You could just use a normal space, but using \s makes your intent more clear and you haven't put in a normal space by accident
  2. The metacharacter \d matches any digit (0-9)
  3. The "operator" + means "the item before me, at least once and as many times as possible"
  4. . is the metacharacter for "match any character", so represent a literal "." we need to "escape" it with a preceding backslash -- \.
  5. The metacharacter $ "anchors" your pattern to the end of the text being considered

Putting those together with the earlier, precise, description you get:

/Tagesplan\sSW\s\d+\.numbers$

"The string /Tagesplan then a space then SW then a space then one or more digits then .numbers then the end of the text."

And you just need to change your condition from "contains" to "matches", since "matches" means "treat this as a Regular Expression".

All the above looks much more complicated than it actually is. Don't worry about learning it all, everything can be looked up -- but it's good to know that this ability to "precisely match something that can vary" is there for when you need it.

2 Likes

Here's another take that doesn't require a "for each," it simply finds and opens the only file that starts with "Tagesplan".

Download Macro(s): Open file with variable name.kmmacros (3.6 KB)

Macro screenshot

Macro notes
  • Macros are always disabled when imported into the Keyboard Maestro Editor.
    • The user must ensure the macro is enabled.
    • The user must also ensure the macro's parent macro-group is enabled.
System information
  • macOS 14.7
  • Keyboard Maestro v11.0.3

I can't test with your path, obviously, but this worked fine when I tested with the path to a file on my Desktop.

How it works: The ls command will list all files in the path that start with "Tagesplan." In Keyboard Maestro, if that command returns an error (i.e. no files found), then the variable isn't set and will be empty.

If that's the case, the macro displays an error message and quits. But if there's a value in the variable, because you've said there will only ever be one file there, the macro opens it.

-rob.

2 Likes

If going that route, you could skip ls and go straight to open:

image

...which saves a (hopefully unnecessary) "If... Then 'Open'" when the file is there, and has the benefit (or not!) of opening everything that begins with "Tagesplan" should there be more than one, so you can choose which you want to keep open

3 Likes

The funny thing is that I basically wrote it this way first, but then thought "no, wait, what if something goes wrong with Hazel and there are dozens of files there?" I thought it'd be annoying if they all opened up :).

And actually, I'd probably make the macro a bit longer, now that I consider the multiple matches thing in more detail: Instead of erroring out, it could notify when more than one file was found:

Download Macro(s): Open file with variable name.kmmacros (6.0 KB)

Macro screenshot

Macro notes
  • Macros are always disabled when imported into the Keyboard Maestro Editor.
    • The user must ensure the macro is enabled.
    • The user must also ensure the macro's parent macro-group is enabled.
System information
  • macOS 14.7
  • Keyboard Maestro v11.0.3

I guess it depends on how @Johnkree wants to handle situations when more than one file is found.

The beauty—and curse—of Keyboard Maestro is that there's always more than one way to do something :).

3 Likes

If that applies to all subfolders in your home directory, then you can solve the problem in a single command: (but you should probably test this command to be sure)

image

By default, KM shell scripts are run from / -- combined with the d option, that's unlikely to work.

The file appears to be in OP's iCloud Drive. But even rooting the command there will probably be a worse option (shell instantiation cost) than the "For Each"s above -- unless OP has hundreds (thousands?) of files at the top level of iCloud Drive.

Oops. I should have known that. But it shouldn't be too hard to fix that. Let me ponder.

Hmm, replacing PWD with HOME in my script seems to be working, but there's still a small delay, and I'm not sure why that is. Hmm, I think I understand the issue now, and I'm trying to solve it by using a symbolic link. Hmm, symbolic links was a valiant attempt, but it didn't work, so now I have to try another approach. In any case, the delay isn't very large, so my HOME solution may work for some people.

Okay the reason why my solution "takes a few seconds" is because I didn't realize that my HOME directory contains a lot more files than I expected, probably related to my iCloud connections. But apart from that short delay, my solution (using HOME instead of PWD) is pretty effective. I can also achieve the same result using "find" instead of "ls", but one solution is enough.

Depends on what you mean by "all subfolders in your home directory". If you mean "to any depth" then, no. If you mean "only the folders in your home directory, not their subfolders", then yes. DUCY?

find will work much better in this case, allowing for a recursive search (which you could depth control so it didn't go stupidly deep).

mdfind would be even better -- why search the file tree when you can search the Spotlight index?

But (unless you are chasing a general solution) since you know where the OP's file is there's no need for any of this -- just target the right directory in the first place.

I had to google the term "DUCY". My response is no, I have no idea what you mean. I was saying that "some people" may be satisfied with my solution. And I think you were disagreeing with that, although I can't really tell what your reasoning is. For people who have a small number of files in their home directory, even if they have dozen of subdirectories, my solution will work, and I can't see why you would disagree with that. You didn't state your reason for disagreeing.

Yes, hardcoding a path can be a very good solution, but my solution works independent of any path. I prefer solutions in which you don't have to hardcode a path. (Also, that means any solution I upload will work immediately for the user without the user having to change the path.) Don't forget, he said "it changes every year" and my solution will work even when the path changes each year.

1 Like

What is ** in the path? What does that require to work?

We all know you are much, much smarter than me, so you already know the answer. Here's a screenshot explaining what it does...

1 Like

Not smarter -- just bitten by this before. And I was hoping to convince you to work it out, given some clues. But to save time...

Globstar was introduced in bash v4, but macOS ships with bash v3.2 -- no globstar (you can't even enable it with shopt -s globstar). And KM's "Execute a shell script" uses sh, which is actually the macOS bash in sh-compatability mode.

So either you've installed a third-party bash v4 or 5 and have got KM's action to default to that, you've got KM defaulting to zsh instead of sh, or your KM shell script isn't behaving as you think it does from your Terminal tests of the same.

If it's the first two then that's undocumented in your posts, so not knowing to do the same will catch everyone out. But I suspect it is the last, which means your command (changing it to use $HOME) is the same as

open `ls -d "$HOME"/*/*Tagesplan*`

...so would include, for example

/Users/airy/Documents/Tagesplan SW 01.numbers

...but not

/Users/airy/Documents/My Files/Tagesplan SW 01.numbers
2 Likes

Your response was gentle and kind, thanks. I didn't know half of the things you pointed out in your last message. In fact, I think it will take me an hour to understand all your points. Thanks. I did suspect you were trying to give me the opportunity to figure things out for myself, but I wasn't sure.

1 Like