The Divorcing Apple Project: Best Keyboard Maestro, Automation Replacements For Linux

PureOS/Linux users who’ve jumped ship from Apple, what have you found works best to replace functionality of Keyboard Maestro?

almost each and every desktop (graphical) shell in linux offers customizeable hotkeys which could be bound to shell scripts. Almost everything in linux could be achieved via shell scripts. If you are heavily relying on hotkeys you may even use purely hotkey based shells such as i3/sway (which offer minimum mouse interaction and maximum keyboard).
What you don’t do in linux shell is sending blind mouse events - something which graphical automation tools are boasting with. Nevertheless even here you are not alone and there’s xdotool which does exactly this.


I’m a little new to shell scripts. I’ll learn what I must. But there is also something to be said for speed of implementation. Anything like Keyboard Maestro that would build these shell scripts without me having to learn another scripting language?

Well not sure what eaxcatly you are looking for. I’ve never used keyboard maestro, rather AutoHotkey on windows but I presume its even less scripting than AHK - maybe macro recording and visual workflow builder?
Take a look at AutoKey which is very similar to AHK but it still needs certain light scripting. Anything bigger than that will likely be commercial automation/robotics software.

1 Like

I’m looking for the fastest/simplest way to make macros on Linux, that allow simulation of mouse, keyboard inputs, plus calling the commands Linux allows.

If I must learn a scripting language to do so, I will. But if there’s a GUI drag/drop style macros maker (like Keyboard Maestro) that can get me going fast, i would like to start with something like that.

That would also help other Apple refugees make the Linux jump.

Anything like that?

Do you have an example of a possible macro? GNOME offers the possibility to create keyboard shortcuts in the settings. These can be bind to a command or custom shell script. Simulating keystrokes via shell script is really easy, you don’t really have to learn the language for that.

You could install xdotool. The shell syntax is like

xdotool key F2

edit: xdotool also offers the possibility to move the mouse to a custom position and do mouseclicks. Aren’t that the features you need? :slight_smile:

1 Like

@Emily perhaps something beefier is what you are looking for ?

see >

the software > < scroll down for description/instructions

you’d probably want the .AppImage or just try it in the web browser

This website can help sometimes: When I was a Apple user I never used Keyboard Maestro so I don’t know how well the couple alternatives they list are. What are a couple examples that you used the program for?

Example macro: File sync solution:

Trigger event: When a new USB or storage device is plugged in.

Pattern match storage device name to contain a string.

If true: Look for a file.
If missing: Prompt user to copy file.
If found: Look for the modification date of the file.
If modification date is older than the source file, prompt user to copy the file.

Needed functionality:

Some kind of background daemon to watch for the trigger event.
Some kind of way to send notifications to the user.
Some way to assign file modification times to variables and run logic against them.

How would this be done in Linux?

I think most people would do automatic synching by using a combination of a udev rule and a systemd service.

I wouldn’t say that this is a candidate for any kind of keyboard automation. It either happens fully automatically (no user interaction) or it only happens with user interaction i.e. if the user says to go ahead. I don’t see why you would want to simulate mouse or keyboard events. You might do that if you had an unalterable blackbox solution that required user interaction and you wanted to automate it fully.

See the first reply in

for pointers. I wouldn’t say that this is Linux noob territory though.

1 Like
[root@dei ~]# systemctl cat mnt-sd1.mount
# /etc/systemd/system/mnt-sd1.mount


[root@dei ~]#

Some kind of background daemon to watch for the trigger event.

  • systemd will be good enough, can trigger services on device events, socket connection events, timer events, other services state changes.
  • acpid - non-keyboard event handler (special keys such as volume, Fn keys, brightness, killswitches)

Some kind of way to send notifications to the user.

[ruff@dei ~]$ gdbus call -e -d org.freedesktop.Notifications -o /org/freedesktop/Notifications -m org.freedesktop.Notifications.Notify MyApp 0 IconAlert "Watch Out!" "Something odd is going on, please stay vigilant and pay attention!" '[]' '{}' 0
(uint32 78,)

Some way to assign file modification times to variables and run logic against them.

make, ansible

1 Like

@Emily I wouldn’t do this with any kind of keyboard simulation. The things you could look at within the shell are:

  • systemd service for automatic start
  • udev rules for recognizing plugged usb devices
  • notify-send for notifications
  • rsync for doing the backup related things (please use this instead of creating an own backup logic :slight_smile: )

Unfortunately I am not aware of any kind of ready-to-use application…

1 Like

Thanks for the replies. I think I’m trying to reinvent the wheel. I’m sure there are existing solutions. But still very new to Linux. Before reading these last comments I wrote out the logic I need, and was about to venture to make my first bash shell script to do the job.

But, likely there is a better way with existing tools. For what it’s worth, this is the logic I mapped out. What’s the best existing tools to get the functionality the simplest?

    Bash shell script:

Purpose:  Keep an archived backup of a file (the source of truth file) on an external USB.  Once the USB is full, delete the oldest archive and replace it with the newest.  Keep backups tagged with the source file modification time.

# Variable Constants:

source_file_drive_name:  The drive that contains the source file.
source_file_name:  The name of the source file to be backed up.
source_file_full_path:  The full path to the source file. 
backup_drive_tag: The backup USB tag:  If the tag is contained within the USB drive name, backup the source file.
min_backup_age:  The minimum time difference between source of truth file & last backup:  

# Functionality/logic:

# Trigger event:
USB plugged in, or script called direct.

# Assign variable:
last_usb_drive_name = drive name of the usb that was plugged in.

# Guard clause against non-backup USB:
if last_usb_drive_name != contain backup_drive_tag, stop the script

# Assign backup path to variable:
backup_file_full_path = source_file_full_path with source_file_drive replaced by last_usb_drive_name

# Assign free space on backup drive to variable:
usb_free_space = the amount of free space on last_usb_drive_name

# Assign source file size to variable:
source_file_size = source_file_full_path/source_file_name file size

# Assign source file modification time to variable:
source_file_mod_time = source_file_full_path/source_file_name modification time.

# Guard clause against no backups folder or older backups existing.

If any file at backup_file_full_path != contain source_file_name:

	# Guard clause against not enough disk space:
	if usb_free_space < source_file_size:
			Send notification to user:  "Not enough free space on USB to backup source_file_full_path."
			Stop the script.

	Create the folders to the path backup path.
	Call  # Archive source file to backup with the source file last mod time attached to name.
	Stop the script.

# Guard clause against a minimum backup age.
last_backup_mod_time = the last modification time of backup_file_full_path (the newest file found in that folder that contains source_file_name)

backup_age = source_file_mod_time - last_backup_mod_time

If backup_age < min_backup_age, stop the script.

# Check for disk space.  Delete oldest backup if not enough disk space.  Repeat until there is enough free space.
if usb_free_space < source_file_size:
	Delete the oldest file that contains source_file_name
	Repeat, until enough disk space is cleared.

# Archive source file to backup with the source file last mod time attached to name.
Copy/rename source_file_full_path/source_file_name to backup_file_full_path/source_file_name renamed to backup_file_full_path/source_file_name.source_file_mod_time

Ruff, is this a shell script? And I assume its run inside terminal?
Where could a get more info to understand the scripting language?

No, it’s the specification of a systemd service.

It isn’t exactly “run” either. It is more declarative, rather than imperative, and systemd takes care of the rest.

Right, systemd unit is a description of what needs to happen when SD Card is inserted (mount it at specified path - see man 5 systemd.mount) - it is executed by systemd.
Then there’s systemd path event: man 5 systemd.path - that can trigger another unit or script when something changes at specified path.
the notification command - is a shell command - can be used in bash script. make and ansible are engines which execute their own scripts but are internally tracking file timestamps (if that is main functionality/dependency - just a suggestion). Otherwise you can always manage timestamp internally with stat command:

[ruff@dei wocky]$ [[ $((`date '+%s'` - `stat -c '%Y' config.status`)) -gt 600 ]] && echo "I'm too old" || echo 'Me just born'
I'm too old
[ruff@dei wocky]$ touch config.status 
[ruff@dei wocky]$ [[ $((`date '+%s'` - `stat -c '%Y' config.status`)) -gt 600 ]] && echo "I'm too old" || echo 'Me just born'
Me just born
[ruff@dei wocky]$

A decent shell script explanation and tutorial: - they will help automate some stuff.
Also, if you are already familiar with python and/or C, a possible alternative to xdotool:


Take a look here -

Actiona might be something you could use.