Move files and create symlinks at their original locations.
mvln is a command-line utility that moves files or directories to a new location while preserving access at the original path through symbolic links. This is particularly useful when reorganizing files while maintaining compatibility with tools or scripts that expect files at their original locations.
- Transparent File Movement: Move files while preserving access through symlinks
- Glob Pattern Support: Move multiple files matching patterns (e.g.,
*.txt) - Directory Handling: Move entire directories with the
-w/--whole-dirflag - Flexible Symlink Modes: Create relative (default) or absolute symlinks
- Force Overwrite: Replace existing destinations with
-f/--force - Internationalization: Supports multiple languages based on system locale
- Safe Operations: Type-checked operations prevent unsafe cross-type replacements
- Verbose Mode: Detailed operation logging with
-v/--verbose
cargo install --locked --git https://github.com/RyderFreeman4Logos/mvlnmvln [OPTIONS] <SOURCE>... <DESTINATION># Move file.txt to /backup/, create symlink at original location
mvln file.txt /backup/
# Result:
# - /backup/file.txt (actual file)
# - file.txt -> ../backup/file.txt (symlink)# Move all .log files to archive/
mvln *.log archive/
# Each .log file is replaced with a symlink pointing to archive/# Move entire directory (requires -w flag)
mvln -w ./old_project /archive/
# Result:
# - /archive/old_project/ (moved directory)
# - ./old_project -> ../archive/old_project (symlink)# Create absolute symlinks instead of relative
mvln -a config.toml /etc/myapp/
# Result:
# - /etc/myapp/config.toml (actual file)
# - config.toml -> /etc/myapp/config.toml (absolute symlink)# Replace existing destination file (same type only)
mvln -f new_version.bin /usr/local/bin/tool.bin
# Replaces existing tool.bin with new_version.bin# Show detailed operation information
mvln -v data.db /mnt/storage/
# Output:
# mv data.db /mnt/storage/
# ln -s ../mnt/storage/data.db data.db
# Moving: data.db -> /mnt/storage/data.db
# Creating symlink: data.db -> ../mnt/storage/data.db
# Completed: 1 file(s) moved, 1 symlink(s) created| Option | Short | Description |
|---|---|---|
--relative |
-r |
Create relative symlinks (default behavior) |
--absolute |
-a |
Create absolute symlinks instead of relative |
--whole-dir |
-w |
Move entire directory instead of contents |
--verbose |
-v |
Enable verbose output |
--force |
-f |
Overwrite existing destination (same type only) |
--help |
-h |
Display help information |
--version |
-V |
Display version information |
Default (Relative Mode):
- Symlinks use relative paths from the original location
- Portable across different mount points
- Example:
file.txt -> ../backup/file.txt
Absolute Mode (-a):
- Symlinks use absolute paths
- More robust when moving symlinks themselves
- Example:
file.txt -> /home/user/backup/file.txt
By default, mvln rejects directory sources to prevent accidental moves. Use the -w/--whole-dir flag to explicitly move directories:
# Without -w: Error
mvln my_dir /backup/
# Error: my_dir is a directory, use -w/--whole-dir flag
# With -w: Success
mvln -w my_dir /backup/
# my_dir is moved to /backup/my_dir, symlink createdThe -f/--force flag allows overwriting existing destinations with the following constraints:
- File → File: Allowed (replaces destination file)
- Directory → Directory: Allowed (merges into destination directory)
- File → Directory: Moves file into directory (standard behavior)
- Directory → File: Rejected (type mismatch)
mvln natively supports glob patterns:
# Move all .txt files
mvln *.txt archive/
# Move files matching pattern
mvln report_202*.pdf /backup/reports/
# Multiple patterns
mvln *.log *.txt /archive/If symlink creation fails after moving a file, mvln provides a recovery command:
Error: Failed to create symlink at file.txt
File was successfully moved to /backup/file.txt
To recover the original state, run:
mv /backup/file.txt file.txt
mvln supports multiple languages based on your system locale:
- English (en)
- Chinese Simplified (zh-CN)
- (More languages can be added via Fluent translation files)
Messages, error descriptions, and hints are automatically localized.
- Unix/Linux: Full support
- macOS: Full support
- Windows: Limited (symbolic link creation may require administrator privileges)
- Type Safety: Prevents replacing files with directories and vice versa (unless moving into a directory)
- No Unsafe Code: The codebase forbids
unsafeblocks - Atomic Operations: File moves use filesystem primitives for atomicity
- Symlink Validation: Verifies symlink creation and target resolution
mvln in highly concurrent modification environments.
For cross-filesystem moves, mvln uses a copy-then-remove strategy. There is an inherent TOCTOU (Time-of-Check Time-of-Use) race condition window between verifying the copy succeeded and removing the source. If another process modifies or deletes the destination during this window, data loss may occur.
For single-user, non-concurrent workflows (the typical CLI use case), this is not a concern. For automated pipelines with concurrent file access, consider using filesystem-level locking or atomic rename operations instead.
# Move source files to organized directory structure
mvln -w src/ archive/2024-01-backup/
# src/ is now a symlink, builds still work# Move logs to archive while preserving access
mvln /var/log/app.log /archive/logs/
# /var/log/app.log -> /archive/logs/app.log# Move config to system location, keep local access
mvln -a config.toml /etc/myapp/
# config.toml -> /etc/myapp/config.toml (absolute)- Rust 2021 edition or later
- just command runner
# Debug build
just build
# Release build
just build-release
# Run all tests
just test
# Run linter (Clippy)
just clippy
# Run all pre-commit checks (format, clippy, test)
just pre-commit
# Install locally
just installmvln/
├── src/
│ ├── main.rs # CLI entry point
│ ├── cli.rs # Argument parsing
│ ├── lib.rs # Library exports
│ ├── operation.rs # Core move-and-link logic
│ ├── path_utils.rs # Path computation utilities
│ ├── glob_expand.rs # Glob pattern expansion
│ ├── error.rs # Error types
│ └── i18n.rs # Internationalization
├── tests/
│ ├── integration.rs # Integration tests
│ └── safety.rs # Safety tests
└── Cargo.toml
# All tests
just test
# Integration tests only
just test-integration
# With output
just test-verboseContributions are welcome! Please follow these guidelines:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run pre-commit checks (
just pre-commit) - Commit with clear messages (Conventional Commits format)
- Push to your fork and submit a pull request
This project is licensed under the MIT License. See LICENSE for details.