A fast, keyboard-driven two-panel file manager for macOS and Linux, inspired by Midnight Commander. Built entirely with Python's standard library — zero dependencies required.
/Users/you │ /Users/you/Downloads
NAME SIZE MODIFIED │ NAME SIZE MODIFIED
Documents/ <DIR> Mar 10 │ ubuntu-24.04.iso 4.7 GB Mar 13
*Projects/ <DIR> Mar 15 │* setup_vscode.exe 92.0 MB Mar 11
readme.txt 2.1 KB Mar 01 │ archive.tar.gz 230 MB Mar 12
notes.md 5.8 KB Mar 09 │ photo_vacation.zip 1.4G Mar 08
──────────────────────────────────────────────────────────────────────────────────────
4 items free: 128 GB 2 selected [COPY: 2]
SPC Sel a SelAll F5/c Copy→ F6/m Move→ y Yank x Cut p Paste P Paste+Rename
Ent Open Bksp Parent Tab Switch F2/r Rename F8/n MkDir D Delete . Hidden q Quit
- Two-panel layout — navigate source and destination simultaneously
- Multi-select — mark any number of files with
Space, operate on all at once - Clipboard workflow — yank/cut files and paste them anywhere, across any directory
- Copy & Move — direct copy/move to the opposite panel with one key
- Rename — inline editor with pre-filled current name
- New directory — create nested directories instantly
- Delete — with confirmation dialog, no accidental deletes
- Symlink aware — follows symlinks on
Enter, marks them with@ - Executable detection — marks runnable files with
* - Hidden files toggle — show/hide dotfiles with
. - macOS Terminal integration — open a new Terminal window at the current directory with
s - Auto-rename on conflict — paste with
Prenames duplicates asfile_1.txt,file_2.txt, etc. - Full keyboard navigation — arrow keys, Page Up/Down, Home/End
- Works on
/Applications— handles macOS.appbundles and system permission boundaries gracefully
| Requirement | Version |
|---|---|
| Python | 3.10 or later |
| OS | macOS (Darwin) or any POSIX/Linux system |
| Dependencies | None — uses only the Python standard library (curses, shutil, pathlib) |
# Clone the repo
git clone https://github.com/yingtze/fm.git
cd fm
# Make executable
chmod +x fm.py
# Run
python3 fm.pyOr drop fm.py anywhere on your $PATH:
cp fm.py /usr/local/bin/fm
chmod +x /usr/local/bin/fm
fm| Key | Action |
|---|---|
↑ ↓ / k j |
Move cursor up / down |
Page Up / Page Down |
Scroll one page |
Home / End |
Jump to first / last item |
Enter |
Open directory / follow symlink |
Backspace |
Go to parent directory |
Tab |
Switch active panel |
| Key | Action |
|---|---|
Space |
Toggle select on cursor (cursor stays) |
a / F7 |
Select all — press again to deselect all |
Escape |
Clear all selections |
Note:
Spaceintentionally does not move the cursor. This lets you visually confirm each selection. Press↓manually to advance to the next file.
| Key | Action |
|---|---|
y |
Yank — copy selected file paths to clipboard |
x |
Cut — mark selected files for move on paste |
p |
Paste here — skip files that already exist |
P |
Paste here — auto-rename conflicts (file_1.txt) |
The status bar shows a [COPY: N] or [CUT: N] badge while the clipboard is active. Files in the clipboard are marked with # (yank) or % (cut) in the file list.
| Key | Action |
|---|---|
F5 / c |
Copy selected items to the other panel |
F6 / m |
Move selected items to the other panel |
F2 / r |
Rename item under cursor |
F8 / n |
Create a new directory |
D / Delete |
Delete selected items (with confirmation) |
| Key | Action |
|---|---|
. |
Toggle hidden files (dotfiles) |
R |
Reload / refresh both panels |
s |
Open macOS Terminal at current directory |
q / F10 |
Quit |
| Mark | Meaning |
|---|---|
* |
File is selected |
# |
File is in clipboard (yank / copy) |
% |
File is in clipboard (cut / move) |
/ |
Directory |
@ |
Symbolic link |
* |
Executable file |
Select a range of files:
Navigate with ↓, press Space on each file you want — the cursor stays in place so you can see what's selected before moving on.
Copy files between two different directories:
- Navigate the left panel to your source directory
- Navigate the right panel to your destination
- Select files in the active panel
- Press
F5orcto copy
Yank and paste to multiple destinations:
- Select files and press
yto yank - Navigate to the first destination, press
pto paste - Navigate to the second destination, press
pagain — clipboard stays active until you cut/yank something new or the files are moved
Open /Applications:
Navigate to /Applications — .app bundles are shown as directories (they are directories on macOS). Press Enter to browse inside.
There is no configuration file by default. Behaviour can be changed by editing constants at the top of fm.py:
HIDDEN_SHOW = False # Set to True to show hidden files on startupMIT License — see LICENSE for details.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
- Fork the repository
- Create your feature branch (
git checkout -b feature/my-feature) - Commit your changes (
git commit -m 'Add some feature') - Push to the branch (
git push origin feature/my-feature) - Open a Pull Request