A simple S3 command-line tool with an SFTP-like workflow.
Config path:
~/.config/bucketctl/config.toml
Override it with -c <PATH> or --config <PATH>:
bucketctl -c ./my-config.tomlGenerate a template with bucketctl init:
bucketctl initDefine multiple profiles — one per bucket:
[settings]
default_profile = "bitiful"
[bitiful]
bucket = "abcde"
endpoint = "https://s3.bitiful.net"
region = "cn-east-1"
access_key = "env:ACCESS_KEY"
# access_key = "YOUR_ACCESS_KEY"
secret_key = "env:SECRET_KEY"
# secret_key = "YOUR_SECRET_KEY"
path_style = false
# optional: download objects via your CDN domain instead of the S3 endpoint
# cdn_domain = "https://cdn.example.com"
[cloudflare-r2]
bucket = "assets"
endpoint = "https://xxx.r2.cloudflarestorage.com"
region = "auto"
access_key = "xxx"
secret_key = "xxx"
path_style = truedefault_profile is optional. When set, most commands target that bucket by default.
cdn_domain is optional. When set, get downloads objects with plain HTTPS from
{cdn_domain}/{key} instead of the S3 endpoint — useful when a CDN accelerates your
bucket. Objects must be publicly readable through the domain; listing and other
operations still use the S3 API.
Install or update the latest matching release:
bash -c "$(curl -fsSL https://github.com/barkure/bucketctl/raw/main/install.sh)" @ installRemove it:
bash -c "$(curl -fsSL https://github.com/barkure/bucketctl/raw/main/install.sh)" @ removeRun without arguments to pick a profile interactively:
$ bucketctlselect a profile:
> bitiful
cloudflare-r2
Use ↑/↓ to navigate, Enter to confirm — the chosen bucket opens in interactive mode.
Operate on the default bucket directly:
bucketctl ls # list default bucket root
bucketctl ls /path/to/dir # list a subdirectory
bucketctl put ~/a.txt /path # upload
bucketctl get /file ./ # download
bucketctl mkdir /new-dir # create directory
bucketctl rm /file # delete file
bucketctl rm -r /dir # delete directory recursivelyTarget a specific bucket with <profile>: prefix or just the profile name (for ls):
bucketctl ls cloudflare-r2 # list that bucket's root
bucketctl ls cloudflare-r2:/2023 # list a subdirectory
bucketctl put ./a.txt cloudflare-r2:/ # upload
bucketctl get cloudflare-r2:/file ./ # download| Command | Default bucket | Specific bucket |
|---|---|---|
| List root | bucketctl ls |
bucketctl ls <profile> |
| List path | bucketctl ls /path |
bucketctl ls <profile>:/path |
| Upload | bucketctl put ./a.txt /path |
bucketctl put ./a.txt <profile>:/path |
| Download | bucketctl get /file ./ |
bucketctl get <profile>:/file ./ |
| Create dir | bucketctl mkdir /dir |
bucketctl mkdir <profile>:/dir |
| Delete file | bucketctl rm /file |
bucketctl rm <profile>:/file |
| Delete dir | bucketctl rm -r /dir |
bucketctl rm -r <profile>:/dir |
~in local paths is expanded to your home directory.
Once in the REPL (entered via profile picker above), the following commands are available:
| Command | Description |
|---|---|
ls [path] |
List directory |
cd [path] |
Change directory |
pwd |
Print working directory |
mkdir <remote-dir> |
Create directory |
put <local> [remote] |
Upload file |
get <remote> [local] |
Download file |
rm <remote> |
Delete file |
rm -r <remote-dir> |
Delete directory recursively |
help |
Show help |
exit / Ctrl-D |
Exit REPL |
!<cmd> |
Run local shell command |
Ctrl-C |
Cancel current transfer |
Add to your shell config file:
# bash (~/.bashrc) or zsh (~/.zshrc)
alias bkt='bucketctl'
# fish (~/.config/fish/config.fish)
alias bkt='bucketctl'Reload your shell, then use bkt instead of bucketctl.
