Easy SSH file copy CLI tool with persistent server selection
Project description
sshcp
Easy SSH file copy CLI tool with persistent server selection, bookmarks, rsync sync, and 2-way watch mode.
No more typing long scp user@host:/path/to/file commands. Just select your server once and copy files with ease.
Features
- Interactive server selection - Arrow-key navigation from
~/.ssh/config - Persistent server selection - No need to re-select every time
- Bookmarks - Save frequently used remote paths
- Rsync sync - Efficient incremental directory syncing
- Watch mode - 2-way sync with conflict resolution
- Beautiful terminal UI - Rich formatting and progress display
Installation
Using npx (easiest)
npx sshcp --help
npx sshcp set
Requires Python and uv or pipx installed.
Using uv (recommended for Python users)
# Run without installing
uvx sshcp --help
# Or install globally
uv tool install sshcp
Using pip
pip install sshcp
From source
git clone https://github.com/shubham8550/sshcp.git
cd sshcp
uv sync
uv run sshcp --help
Quick Start
# 1. Select your server (arrow keys to navigate)
sshcp set
# 2. Copy files
sshcp push ./local_file.txt /remote/path/
sshcp pull /remote/file.txt ./local/
# 3. Use bookmarks for frequent paths
sshcp bookmark add logs /var/log/myapp
sshcp pull @logs/error.log ./
# 4. Sync directories efficiently
sshcp sync ./src /var/www/app
# 5. Watch and auto-sync changes
sshcp watch ./project /deploy/app
Commands
Server Selection
sshcp set
Interactive server selector with arrow-key navigation:
╭─ Select SSH Server ─────────────────────────────────╮
│ Name Host User Port │
│ prod 192.168.1.100 deploy 22 │
│ ▸ staging staging.example admin 22 │
│ dev 10.0.0.50 dev 2222 │
╰─────────────────────────────────────────────────────╯
↑/↓ navigate • Enter select • q quit
sshcp status
Show currently selected server with details.
File Transfer
sshcp push <local> <remote>
Upload a file or directory to the selected server.
sshcp push ./myfile.txt /home/user/myfile.txt
sshcp push ./folder /remote/destination/
sshcp pull <remote> <local>
Download a file or directory from the selected server.
sshcp pull /var/log/app.log ./app.log
sshcp pull /etc/nginx ./nginx_config/
Bookmarks
Save frequently used remote paths for quick access.
sshcp bookmark add <name> <path>
Create a new bookmark:
sshcp bookmark add logs /var/log/myapp
sshcp bookmark add config /etc/nginx
sshcp bookmark add deploy /var/www/production
sshcp bookmark list
Show all saved bookmarks:
╭─────────────── Saved Bookmarks ───────────────╮
│ Name Path Usage │
│ @logs /var/log/myapp @logs/... │
│ @config /etc/nginx @config/... │
│ @deploy /var/www/production @deploy/... │
╰───────────────────────────────────────────────╯
sshcp bookmark rm <name>
Remove a bookmark.
Using Bookmarks
Use @bookmark syntax in any path:
sshcp pull @logs/error.log ./ # → /var/log/myapp/error.log
sshcp push nginx.conf @config/ # → /etc/nginx/
sshcp sync ./src @deploy # → /var/www/production
Sync (Rsync)
Efficient incremental directory syncing using rsync.
sshcp sync <local> <remote> [options]
# Push local to remote (default)
sshcp sync ./local_folder /remote/folder
# Pull remote to local
sshcp sync ./local_folder /remote/folder --pull
# Delete files not in source
sshcp sync ./src @deploy --delete
# Preview changes without executing
sshcp sync ./src /remote --dry-run
# Exclude patterns
sshcp sync ./project /deploy --exclude "*.log" --exclude "node_modules"
Options:
| Option | Short | Description |
|---|---|---|
--pull |
-p |
Pull from remote to local (default is push) |
--delete |
-d |
Delete files not present in source |
--dry-run |
-n |
Preview changes without executing |
--exclude |
-e |
Exclude patterns (can be used multiple times) |
Watch Mode (2-Way Sync)
Monitor directories and sync changes bidirectionally in real-time.
sshcp watch <local> <remote> [options]
# Start watching (prompts on conflict - default)
sshcp watch ./src /var/www/app
# With bookmark
sshcp watch ./project @deploy
# Custom poll interval
sshcp watch ./src /app --interval 10
# Auto-resolve conflicts
sshcp watch ./src /app --on-conflict local # Always use local
sshcp watch ./src /app --on-conflict remote # Always use remote
sshcp watch ./src /app --on-conflict newer # Keep newer version
sshcp watch ./src /app -c skip # Skip conflicts
Output:
╭─────────── Watch Mode Active ───────────────────────╮
│ Local: /Users/me/project/src │
│ Remote: myserver:/var/www/app │
│ Mode: 2-way sync │
╰─────────────────────────────────────────────────────╯
Press Ctrl+C to stop
[12:34:56] → Updated: src/app.py
[12:35:10] ← Downloaded: config/settings.json
[12:35:20] ⚠ CONFLICT: data/cache.db
Conflict Resolution:
When both local and remote versions of a file change, you'll see:
╭─────────────── ⚠ Conflict Detected ─────────────────╮
│ File: data/cache.db │
│ │
│ Local Remote │
│ Modified 2024-01-13 12:35 2024-01-13 12:34 │
│ Size 1.2 KB 1.3 KB │
│ │
│ Local is newer │
│ │
│ [L] Keep local [R] Keep remote [S] Skip [Q] Quit │
╰─────────────────────────────────────────────────────╯
Options:
| Option | Short | Description |
|---|---|---|
--interval |
-i |
Seconds between remote polling (default: 5) |
--on-conflict |
-c |
Conflict resolution mode (default: ask) |
Conflict Resolution Modes:
| Mode | Description |
|---|---|
ask |
Prompt user for each conflict (default) |
local |
Always keep local version |
remote |
Always keep remote version |
newer |
Keep the newer version by timestamp |
skip |
Skip conflicting files |
Configuration
SSH Config
sshcp reads hosts from ~/.ssh/config:
Host prod
HostName 192.168.1.100
User deploy
IdentityFile ~/.ssh/id_rsa
Host staging
HostName staging.example.com
User admin
Port 22
sshcp Config
Configuration is stored in ~/.config/sshcp/:
config.json- Selected serverbookmarks.json- Saved bookmarks
Requirements
- Python 3.10+
- OpenSSH (for
scpandsshcommands) - rsync (for sync command)
- SSH config file with configured hosts
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sshcp-0.2.2.tar.gz.
File metadata
- Download URL: sshcp-0.2.2.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
272d6cf527a51021cbd740321d5caf236063eb2dd6f38cd8c0e6a5f28bdee6e2
|
|
| MD5 |
1aa1a3c31687499e9fdbeb86d163107f
|
|
| BLAKE2b-256 |
06004ae8b0d7c71d1774b5b758647f817908d3be01aade276089a1d0251e17d4
|
Provenance
The following attestation bundles were made for sshcp-0.2.2.tar.gz:
Publisher:
publish.yml on shubham8550/sshcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sshcp-0.2.2.tar.gz -
Subject digest:
272d6cf527a51021cbd740321d5caf236063eb2dd6f38cd8c0e6a5f28bdee6e2 - Sigstore transparency entry: 821118651
- Sigstore integration time:
-
Permalink:
shubham8550/sshcp@6a3193d3003eb8472f7f21dfeea566cf3b4d4384 -
Branch / Tag:
refs/tags/0.2.2 - Owner: https://github.com/shubham8550
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6a3193d3003eb8472f7f21dfeea566cf3b4d4384 -
Trigger Event:
release
-
Statement type:
File details
Details for the file sshcp-0.2.2-py3-none-any.whl.
File metadata
- Download URL: sshcp-0.2.2-py3-none-any.whl
- Upload date:
- Size: 22.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
571ba739c3468da1b3fe28204542c25c98257493b4e49eaf496e50b409424e87
|
|
| MD5 |
9840814d63cc2dddbdfa166d717486bd
|
|
| BLAKE2b-256 |
7f28a095773c4cd82767378db2fc46100b0c8ebaff8eef8d2a6078a0c30ec7e3
|
Provenance
The following attestation bundles were made for sshcp-0.2.2-py3-none-any.whl:
Publisher:
publish.yml on shubham8550/sshcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sshcp-0.2.2-py3-none-any.whl -
Subject digest:
571ba739c3468da1b3fe28204542c25c98257493b4e49eaf496e50b409424e87 - Sigstore transparency entry: 821118656
- Sigstore integration time:
-
Permalink:
shubham8550/sshcp@6a3193d3003eb8472f7f21dfeea566cf3b4d4384 -
Branch / Tag:
refs/tags/0.2.2 - Owner: https://github.com/shubham8550
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@6a3193d3003eb8472f7f21dfeea566cf3b4d4384 -
Trigger Event:
release
-
Statement type: