Action
rsync Command Generator
This action helps you create properly formatted rsync commands for backing up files and folders on macOS. It guides you through selecting source and destination paths, handles spaces in file names correctly, and explains exactly what the command will do.
Features
- Prompts for source and destination paths
- Properly formats paths with spaces
- Option to include –delete flag for exact synchronization
- Provides a clear explanation of what the command will do
- Creates a ready-to-use rsync command
Usage
- Run the action
- Enter the source path (where your files are)
- Enter the destination path (where you want the backup)
- Choose whether to use the –delete option
- Copy the generated command to Terminal
Tips
- Use Finder’s “Show Path Bar” (View → Show Path Bar) to easily copy file paths
- The –delete option makes the destination an exact copy of the source
- Without –delete, files removed from the source will remain in the backup
Default Options
The command uses these rsync flags:
- -a
: Archive mode (preserves file attributes)
- -z
: Compress during transfer
- -v
: Verbose output
- -h
: Human-readable sizes
Steps
-
script
function getLastFolderName(path) { // Remove trailing slash if it exists path = path.replace(/\/$/, ''); // Split on / and get last non-empty segment return path.split('/').filter(p => p).pop(); } function createRsyncCommand() { // Prompt for source path let sourcePath = Prompt.create(); sourcePath.title = "Source Path"; sourcePath.message = "Enter the path to the files you want to back up"; sourcePath.addTextField("sourcePath", "Path", "/Users/your-name/Desktop/Source Folder"); sourcePath.dismissAction = "Cancel"; sourcePath.addButton("Continue"); let sourceResult = sourcePath.show(); if (!sourceResult) { context.cancel(); } else { let sourceValue = sourcePath.fieldValues["sourcePath"]; if (!sourceValue) { context.fail("Source path is required"); } else { // Prompt for destination path let destPath = Prompt.create(); destPath.title = "Destination Path"; destPath.message = "Enter the path where files should be backed up"; destPath.addTextField("destPath", "Path", "/Volumes/External Drive/Destination Folder"); destPath.dismissAction = "Cancel"; destPath.addButton("Continue"); let destResult = destPath.show(); if (!destResult) { context.cancel(); } else { let destValue = destPath.fieldValues["destPath"]; if (!destValue) { context.fail("Destination path is required"); } else { // Ask about --delete option let deleteOption = Prompt.create(); deleteOption.title = "Include --delete option?"; deleteOption.message = "This will remove files from the destination that don't exist in the source"; deleteOption.dismissAction = "Cancel"; deleteOption.addButton("Yes"); deleteOption.addButton("No"); let deleteResult = deleteOption.show(); if (!deleteResult) { context.cancel(); } else { // Format paths (add quotes if they contain spaces, remove any existing quotes first) let cleanSource = sourceValue.replace(/['"]/g, ''); let cleanDest = destValue.replace(/['"]/g, ''); // Ensure paths end with trailing slash before adding quotes if (!cleanSource.endsWith('/')) cleanSource += '/'; if (!cleanDest.endsWith('/')) cleanDest += '/'; // Add quotes if needed let formattedSource = cleanSource.includes(' ') ? `"${cleanSource}"` : cleanSource; let formattedDest = cleanDest.includes(' ') ? `"${cleanDest}"` : cleanDest; // Get folder names for the message let sourceFolderName = getLastFolderName(cleanSource); let destFolderName = getLastFolderName(cleanDest); // Construct the message let explanation; if (deleteResult === 0) { explanation = `This rsync command will synchronize "${sourceFolderName}" to "${destFolderName}". The --delete option is enabled, which means "${destFolderName}" will become an exact copy of "${sourceFolderName}" - any files in "${destFolderName}" that no longer exist in "${sourceFolderName}" will be removed.`; } else { explanation = `This rsync command will copy all files from "${sourceFolderName}" to "${destFolderName}". Since the --delete option is not used, any existing files in "${destFolderName}" will be kept, even if they've been removed from "${sourceFolderName}". This means "${destFolderName}" may accumulate files over time.`; } explanation += '\n\n'; // Construct the rsync command let command = `rsync -azvh`; if (deleteResult === 0) { command += ` --delete`; } command += ` ${formattedSource} ${formattedDest}`; // Create new draft with the explanation and command let d = Draft.create(); d.content = explanation + command; d.update(); editor.load(d); } } } } } } createRsyncCommand();
Options
-
After Success Default Notification Info Log Level Info
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.