Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Test

on:
push:
branches: [main]
pull_request:

jobs:
shell-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: ShellCheck
uses: ludeeus/action-shellcheck@2.0.0
with:
scandir: '.'
ignore_paths: .github
severity: error
- name: Functional tests
run: bash tests/run.sh
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024-2026 sloth-bash contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
28 changes: 19 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,33 @@
`curl -fsSL https://raw.githubusercontent.com/psygreg/sloth-bash/main/install.sh | bash`

## Features
- **Intuitive response:** just the file name will run it if executable; load a venv if there's any and wrap it in `python3` if it's a *.py* file; or trigger `xdg-open` for other cases.
- **Intuitive response:** just the file name will run it if executable; run a `*.py` file with the local `venv`/`.venv` interpreter when present (without activating it into your shell); or trigger `xdg-open` for other cases.
- **Flatpak redirection:** simplifies running flatpak applications from terminal by making `flatpak run` obsolete through smart command handling. No more `io.github.kolunmi.Bazaar`, just `bazaar` will do the trick!
- **Easily open apps from terminal automatically detaching them** with `detach appname`. Perfect for usage with something like Quake Terminal for Gnome or `yakuake` Also works with *flatpak redirection*, local executables, and *distrobox passthrough*.
- **`cp` and `mv` redirection to `rsync`:** make your file operations more efficient with `rsync`'s delta copies, while also getting it to smartly display progress on larger tasks.
- **Easily open apps from terminal automatically detaching them** with `detach appname`. Perfect for usage with something like Quake Terminal for Gnome or `yakuake`. Also works with *flatpak redirection*, local executables, and *distrobox passthrough*.
- **`cp` and `mv` helpers:** large same-device file copies can show `rsync` progress; directories without `-r` are refused (like GNU `cp`); same-filesystem `mv` stays a real `mv`.
- **Simple file management in your shell:** automatic `ls` after `cd` so you never get lost in your files, and enabled *autocd* shell option so you can navigate your subdirectories more intuitively.
- **Most used zsh shortcuts**: `md`, `rd`, `mkcd`, `take`, `~` and `..` work exactly like zsh, while you can use `cd ...`, `cd ....` and `cd .....` for the other upwards navigation commands.
- **`all`**: selects all files and subdirectories at its location as targets for `rd`, `rm`, `cp` and `mv`.
- **Better autocompletion** with *Tab* key cycling through all options instead of just displaying them.
- **Most used zsh shortcuts**: `md`, `rd` (`rmdir`), `mkcd`, `take`, `~` and `..` work like zsh, while you can use `cd ...`, `cd ....` and `cd .....` for the other upwards navigation commands.
- **`all`**: selects all non-hidden files and subdirectories at its location as targets for `rd`, `rm`, `cp` and `mv`. `rm all` is interactive; `rd all` only removes empty directories.
- **Better autocompletion** with *Tab* key cycling through all options (Shift+Tab goes backwards when supported).
- **FZF shell bindings:** if *fzf* is installed, `sloth-bash` enables the standard Bash integration, including fuzzy history search on `Ctrl+R`.
- **Basic command colors:** enables colored output for `ls`, `dir`, `vdir` and `grep`, plus familiar aliases like `ll`, `la` and `l`.
- **Case-insensitive command parsing:**, `ls`, `Ls`, `lS` or `LS`, your command will always work.
- **Case-insensitive command parsing:** `ls`, `Ls`, `lS` or `LS`, your command will always work (exact name match, not regex).
- **Distrobox passthrough:** enter your distrobox shell with `distroboxname` and pass commands to your distroboxes running `distroboxname command` (and any additional arguments if needed after). As distroboxes follow the user's *`~/.bashrc`* file, sloth-bash also works from within them!

## Optional integrations
- **Starship** is installed by the installer when missing (recommended).
- **fzf** is installed by the installer when missing.
- **Zellij** auto-start is **opt-in**: set `SLOTH_BASH_ZELLIJ=1` in your environment before sourcing sloth-bash.

## Recommended usage
- Install *[Starship](https://starship.rs)* for the complete experience.
- Install *[fzf](https://github.com/junegunn/fzf)* if you want the full fuzzy shell bindings.
- Copy **sloth-bash** to **`~/.sloth-bash`**
- Copy **alias-list** to **`~/.alias-list`**
- Copy **starship.toml** to **`~/.config/starship.toml`** (not required if you don't wanna use *Starship*)
- Copy **alias-list** to **`~/.alias-list`** (customize Flatpak aliases here; updates do not overwrite it)
- Copy **starship.toml** to **`~/.config/starship.toml`** only if you do not already have one
- Add **`source ~/.sloth-bash`** to the end of your `~/.bashrc` file

## Tests
```bash
bash tests/run.sh
```
124 changes: 84 additions & 40 deletions install.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

REPO_RAW="${SLOTH_BASH_RAW_BASE:-https://raw.githubusercontent.com/psygreg/sloth-bash/main}"

# Argument parsing: Check if called from app
APP_MODE=false
Expand All @@ -11,24 +14,47 @@ for arg in "$@"; do
done

# If called from app and SCRIPT_DIR is set, source shared libraries
if [[ "$APP_MODE" == true ]] && [[ -n "$SCRIPT_DIR" ]] && [[ -f "$SCRIPT_DIR/libs/linuxtoys.lib" ]]; then
if [[ "$APP_MODE" == true ]] && [[ -n "${SCRIPT_DIR:-}" ]] && [[ -f "$SCRIPT_DIR/libs/linuxtoys.lib" ]]; then
# shellcheck source=/dev/null
source "$SCRIPT_DIR/libs/linuxtoys.lib"
fi

download() {
local url="$1" dest="$2"
if command -v curl >/dev/null 2>&1; then
curl -fsSL "$url" -o "$dest"
elif command -v wget >/dev/null 2>&1; then
wget -q -O "$dest" "$url"
else
echo "Need curl or wget to download $url" >&2
return 1
fi
}

download_if_missing() {
local url="$1" dest="$2"
if [[ -e "$dest" ]]; then
echo "Keeping existing $dest"
return 0
fi
mkdir -p "$(dirname -- "$dest")"
download "$url" "$dest"
}

header() {
echo "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣠⡀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣀⣤⠤⠴⠖⠚⠛⠉⠉⠉⠀⠀ "
echo "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡀⠀⢰⣸⣶⣇⠀⢰⣿⣿⣷⣤⠤⠴⠖⠒⠛⠉⠉⠁⠀⠀⠀⠀⠀⠀⣀⣀⣤⠤⠶⠀ "
echo "⠀⠀⠀⠀⠀⠀⠀⢀⣰⣴⣇⠀⢰⣾⣿⣄⣼⡿⠿⢿⡟⠛⠉⠉⠁⠀⠀⠀⠀⠀⠀⣀⣀⣠⠤⠤⠖⠚⠛⠉⠉⠀⠀⠀⠀ "
echo "⠀⠀⠀⠀⣀⣠⣤⢾⣿⠽⢼⡛⠋⠉⠉⠁⢸⠀⠀⠈⢻⣄⣀⣠⠤⠤⣶⠒⠚⠋⢉⣉⣠⣤⠤⠤⠤⣤⣀⠀⠀⠀⠀⠀⠀⠀ "
echo "⠀⠟⠋⠉⠉⠀⠀⣾⠃⠀⠈⢻⣀⣠⠤⢤⣿⠀⠀⠀⠀⢿⡇⠀⢀⣤⡿⠗⠒⢚⣏⠉⠱⡄⠀⠀⠀⢸⠈⠙⠲⣄⠀⠀⠀⠀ "
echo "⠀⣤⣀⣀⡤⠤⠶⡿⠀⠀⠀⠀⣿⠀⠀⠀⢿⠀⠀⠀⠀⠘⣇⣴⠃⠀⠻⢤⡸⣿⡿⠏⢀⡿⠀⠀⢠⣏⡀⠀⠀⠈⢷⡀⠀⠀ "
echo "⠀⠉⠁⠀⠀⠀⢰⡇⠀⠀⠀⠀⠸⡆⠀⠀⢸⡁⠀⠀⠀⠀⢹⡏⠀⠀⠀⣰⣿⣗⠓⠒⠛⠀⠀⠀⠀⠀⠉⠓⢦⡀⠀⢳⡄⠀ "
echo "⠀⠉⠁⠀⠀⠀⢰⡇⠀⠀⠀⠀⠸⡆⠀⠀⢸⡁⠀⠀⠀⠀⢹⡏⠀⠀⠀⣰⣿⣗⠓⠒⠛⠀⠀⠀⠀⠀⠉⠓⢦⡀⠀⢳⡄⠀ "
echo "⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⢳⠒⠒⢙⡇⠀⠀⠀⠀⠀⣧⠀⠀⠀⢿⣧⣽⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢳⡀⠀⢷⠀ "
echo "⠀⠀⠀⠀⠀⠀⢸⡇⠀⠀⠀⠀⠀⠈⠁⠀⠘⠃⠀⠀⠀⠀⠀⢻⡀⠀⠀⠈⠛⠛⠀⣠⠞⡉⠉⠳⣄⠀⠀⠀⠀⠀⢳⠀⠘⡇ "
echo "⠀⠀⠀⠀⠀⠀⢸⣇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⣧⠀⠀⠀⠀⠀⢠⠇⣴⣿⣷⠀⠸⡆⠀⠀⠀⠀⢸⠀⠀⡇ "
echo "⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣆⠀⠀⠀⠀⢸⡄⠉⠋⠉⠀⠀⢷⠀⠀⠀⠀⣸⠀⢠⡇ "
echo "⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣆⠀⠀⠀⡼⠁⠀⠀⠀⠀⠀⢸⠀⠀⠀⣰⠃⠀⡼⠀ "
echo "⠀⠀⠀⠀⠀⠀⠀⢹⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢧⡀⢀⠇⠀⠀⠀⠀⠀⠀⣸⠀⣠⠞⠁⠀⡼⠃⠀ "
echo "⠀⠀⠀⠀⠀⠀⠀⢹⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢧⡀⢀⠇⠀⠀⠀⠀⠀⠀⣸⠀⣠⠞⠁⠀⡼⠃⠀ "
echo "⠀⠀⠀⠀⠀⠀⠀⠀⢿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠾⣄⣀⡀⢀⣀⣀⡠⠷⠚⠁⠀⣠⠞⠁ "
echo "⠀⠀⠀⠀⠀⠀⠀⠀⠈⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠉⠁⠀⠀⠀⢀⣠⠞⠃⠀⠀⠀⠀ "
echo "⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠳⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⠖⠋⠁⠀⠀⠀⠀⠀⠀ "
Expand All @@ -37,9 +63,9 @@ header() {
echo " _ _ _ _ _ "
echo " | | | | | | | | | | "
echo " ___| | ___ | |_| |__ ______| |__ __ _ ___| |__ "
echo " / __| |/ _ \| __| '_ \______| '_ \\ / \`_ / __| '_ \\ "
echo " \__ \ | (_) | |_| | | | | |_) | (_| \__ \ | | | "
echo " |___/_|\___/ \__|_| |_| |_.__/ \__,_|___/_| |_| "
echo " / __| |/ _ \\| __| '_ \\______| '_ \\\\ / \`_ / __| '_ \\\\ "
echo " \\__ \\ | (_) | |_| | | | | |_) | (_| \\__ \\ | | | "
echo " |___/_|\\___/ \\__|_| |_| |_.__/ \\__,_|___/_| |_| "
echo
}

Expand All @@ -55,12 +81,8 @@ show_menu() {
echo
read -rp "Enter your choice (1-3): " choice < /dev/tty
case "$choice" in
1)
return 0 # Install or update
;;
2)
return 1 # Remove
;;
1) return 0 ;;
2) return 1 ;;
3)
echo "Ok, bye!"
exit 100
Expand All @@ -78,9 +100,7 @@ show_menu() {
echo
read -rp "Enter your choice (1-2): " choice < /dev/tty
case "$choice" in
1)
return 0 # Install
;;
1) return 0 ;;
2)
echo "Ok, bye!"
exit 100
Expand All @@ -95,44 +115,68 @@ show_menu() {
show_menu
action=$?

sudo -v
remove_source_lines() {
local file="$1"
[[ -f "$file" ]] || return 0
# portable-ish in-place delete of source lines
local tmp
tmp=$(mktemp)
grep -v 'source ~/.sloth-bash' "$file" > "$tmp" || true
mv "$tmp" "$file"
}

if [[ $action -eq 1 ]]; then
echo "Removing sloth-bash..."
rm -f ~/.sloth-bash ~/.alias-list
if [[ -f ~/.bashrc ]]; then
sed -i '/source ~\/.sloth-bash/d' ~/.bashrc
fi
if [[ -f ~/.profile ]]; then
sed -i '/source ~\/.sloth-bash/d' ~/.profile
fi
rm -f ~/.sloth-bash
# Keep ~/.alias-list and starship.toml — user customizations
remove_source_lines ~/.bashrc
remove_source_lines ~/.profile
echo "sloth-bash has been removed."
echo "Note: ~/.alias-list, ~/.config/starship.toml, Starship, and fzf were left in place."
exit 0
fi
if ! which starship > /dev/null; then
sudo mkdir -p /usr/local/bin # ensure the directory exists before attempting to install starship
if [[ ":$PATH:" != *":/usr/local/bin"* ]]; then
export PATH="/usr/local/bin:$PATH"
[[ -f ~/.bashrc ]] && grep -q "/usr/local/bin" ~/.bashrc || echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bashrc

if ! command -v starship >/dev/null 2>&1; then
if command -v sudo >/dev/null 2>&1; then
sudo mkdir -p /usr/local/bin
if [[ ":$PATH:" != *":/usr/local/bin:"* ]]; then
export PATH="/usr/local/bin:$PATH"
if [[ -f ~/.bashrc ]] && ! grep -q '/usr/local/bin' ~/.bashrc; then
echo 'export PATH="/usr/local/bin:$PATH"' >> ~/.bashrc
fi
fi
curl -fsS https://starship.rs/install.sh | sh
else
echo "Starship is not installed and sudo is unavailable; skipping Starship install."
fi
curl -sS https://starship.rs/install.sh | sh
fi
if [ "$APP_MODE" = true ]; then

if [[ "$APP_MODE" == true ]]; then
pkg_install fzf
else
if ! which fzf > /dev/null; then
source <(curl -s https://raw.githubusercontent.com/psygreg/linuxtoys/master/p3/libs/linuxtoys.lib)
if ! command -v fzf >/dev/null 2>&1; then
# shellcheck source=/dev/null
source <(curl -fsS https://raw.githubusercontent.com/psygreg/linuxtoys/master/p3/libs/linuxtoys.lib)
pkg_install fzf --ignore-appends
fi
fi
wget -O ~/.sloth-bash https://raw.githubusercontent.com/psygreg/sloth-bash/main/sloth-bash
wget -O ~/.alias-list https://raw.githubusercontent.com/psygreg/sloth-bash/main/alias-list
wget -O ~/.config/starship.toml https://raw.githubusercontent.com/psygreg/sloth-bash/main/starship.toml

# Core script always updates; user config files are preserved when present.
download "$REPO_RAW/sloth-bash" ~/.sloth-bash
download_if_missing "$REPO_RAW/alias-list" ~/.alias-list
mkdir -p ~/.config
download_if_missing "$REPO_RAW/starship.toml" ~/.config/starship.toml

if [[ -f ~/.bashrc ]]; then
if ! grep -q "source ~/.sloth-bash" ~/.bashrc; then
echo "source ~/.sloth-bash" >> ~/.bashrc
if ! grep -q 'source ~/.sloth-bash' ~/.bashrc; then
echo 'source ~/.sloth-bash' >> ~/.bashrc
fi
else
if ! grep -q "source ~/.sloth-bash" ~/.profile; then
echo "source ~/.sloth-bash" >> ~/.profile
if [[ -f ~/.profile ]] && ! grep -q 'source ~/.sloth-bash' ~/.profile; then
echo 'source ~/.sloth-bash' >> ~/.profile
elif [[ ! -f ~/.profile ]]; then
echo 'source ~/.sloth-bash' >> ~/.bashrc
fi
fi
fi

echo "sloth-bash installed. Open a new shell or run: source ~/.sloth-bash"
Loading
Loading