Skip to content

aiya000/bash-toys

Repository files navigation

🐕 bash-toys 🐕

Tiny Tools that Reach the Finer Details

Shell: bash/zsh License: MIT Dependencies: minimal

📑 Table of Contents

📑 Quick Start

git clone --depth 1 https://github.com/aiya000/bash-toys.git /path/to/bash-toys

If using bash:

echo 'source /path/to/bash-toys/source-all.sh' >> ~/.bashrc

If using zsh:

echo 'source /path/to/bash-toys/source-all.sh' >> ~/.zshrc

📑 Documentation

For detailed documentation with examples and options, see:

See also 'Scripts' section for what is bin and sources.

📑 Scripts

For a complete list of scripts, visit ./bin and ./sources.

🔹 Executables (./bin)

bash-toys scripts have minimal dependencies. These dependencies are documented at the beginning of the script.

Script Description Quick Example Test
bak Toggle backup (.bak) extension for files $ bak file.txt # mv to file.bak.txt Test
bookmark-open (WIP) Opens a selected bookmark in the default browser $ bookmark-open # select & open Test
calc-japanese-remaining-working-hours Calculate required daily working hours for remaining business days $ calc-japanese-remaining-working-hours 80:00 # 80h worked in this month No Test
cat-which A shorthand for cat $(which cmd). Uses bat if available $ cat-which rm-dust # show source Test
clamdscan-full Performs a full virus scan using ClamAV $ clamdscan-full / # scan root Test
confirm Ask a yes/no confirmation question and exit based on the answer $ confirm 'Continue?' # asks y/n Test
ctags-auto Automatically determine git project and generate ctags $ ctags-auto # generate tags No Test
date-diff-seconds Calculate time difference in minutes between two times $ date-diff-seconds 21:47 22:33 # => 46 mins Test
date-diff-seconds-now Calculate time difference between given time and now $ date-diff-seconds-now 22:30 # mins until Test
docker-attach-menu Attach to a Docker container selected from interactive menu $ docker-attach-menu # select & attach No Test
docker-clean-all Remove all Docker containers and volumes at once $ docker-clean-all # clean all No Test
docker-kill-menu Kill a Docker container selected from interactive menu $ docker-kill-menu # select & kill No Test
expects A smaller test API like jest for bash script $ expects "$x" to_be 10 # assert x=10 Test
fast-sync Efficiently sync files from source to target by comparing file lists $ fast-sync /src /dst # sync new only Test
gh-issue-view-select Show GitHub issues in interactive filter and open selected issue $ gh-issue-view-select # select & view Test
gh-run-view-latest Show the latest GitHub Actions run preview and log $ gh-run-view-latest # view latest run No Test
git-credential-gh-switch Git credential helper that switches GitHub account per repository $ # See doc/bin.md Test
git-root Shows the git root directory of the current directory $ git-root # => /path/to/repo No Test
is-in-wsl Check if current shell is running in WSL $ is-in-wsl && echo WSL # detect WSL No Test
kill-latest-started Kill the latest started background process $ kill-latest-started # kill last bg No Test
kill-list Display and kill processes selected from interactive menu $ kill-list # select & kill No Test
list-dpkg-executables List executable files provided by a dpkg package $ list-dpkg-executables git # list bins No Test
notify Send desktop notification with title and message $ notify "Title" "Msg" # show popup No Test
notify-at Send notification at specified time with flexible date formats $ notify-at 12:00 "T" "M" # at noon Test
notify-at-at Send notification at specified time using at command (Linux/WSL) $ notify-at-at 12:00 "T" "M" # Linux No Test
notify-at-launchd Send notification at specified time using launchd (macOS) $ notify-at-launchd 12:00 "T" "M" # macOS No Test
notify-cascade Send cascade of notifications at specified intervals before target time $ notify-cascade 15:00 "M" "M" 30m 5m # 30m,5m before No Test
notify-ntfy Send notification to mobile via ntfy.sh $ notify-ntfy "T" "M" # to mobile No Test
pathshorten Abbreviate file path with shortened parent directories $ pathshorten ~/Documents/Proj # => ~/Docu/Proj No Test
peco-reverse Reverse order interactive filter using peco $ ls | peco-reverse # reversed filter No Test
photoframe Display photos in fullscreen slideshow mode using feh $ photoframe ~/Pictures # slideshow No Test
pomodoro-cycle Run a full pomodoro cycle with multiple work sessions and breaks $ pomodoro-cycle 3 25 25 25 # 3x25min cycle Test
pomodoro-timer A simplest Pomodoro Timer implementation in shell script $ pomodoro-timer 25 # start 25min Test
prompt Display a prompt and wait for the user to press Enter (always exits 0) $ prompt 'Press Enter: ' # pause Test
rm-dust An alternative to rm, moving files to a dustbox instead. Use --restore to recover files. alias rm=rm-dust is recommended! $ rm-dust file.txt # mv to dustbox Test
run-wait-output Run two commands sequentially, with second triggered after first becomes silent $ run-wait-output 1000 "npm watch" "echo Done" # after silent Test
update-audio-file-volume Adjust audio volume to match a target mean/max level using ffmpeg $ update-audio-file-volume --input foo.mp3 --output bar.mp3 --mean-volume -48.7 No Test
skip Skip n-lines from the beginning of output $ seq 10 | skip 3 # => 4,5,...,10 No Test
slice Slice fields from input lines $ echo "a,b,c" | slice , 2 3 # => b,c No Test
start Starts a process in the background without output $ start firefox # run silently No Test
take-until-empty Takes input lines until a blank line appears $ cat file | take-until-empty # stop at blank Test
vim-configure Executes ./configure for Vim source with modern flags $ vim-configure # run ./configure No Test
vim-configure-debug Execute Vim source configure script with debug flags $ vim-configure-debug # with debug No Test
vim-configure-macos Execute Vim source configure script with modern macOS flags $ vim-configure-macos # for macOS No Test

🔹 Sources (./sources)

'Sources' are utility scripts that affect the parent shell (like the cd command).

Script Description Quick Example Test
alias-of Creates an alias only if the command exists $ alias-of rg 'rg --color always' # if rg exists No Test
cd-finddir Shows directories and cd to a selected one via interactive filter $ cd-finddir # fuzzy cd No Test
cd-to-git-root Change directory to the git root, with WSL path recovery support $ cd-to-git-root # cd to repo root No Test
cd-to-node-root Change directory to the nearest parent directory containing package.json $ cd-to-node-root # cd to pkg dir No Test
contains-value Checks if an array contains a value $ contains-value "${arr[@]}" "val" # check in arr No Test
define-alt Defines a shell variable named 'foo' if not defined; use --export to also export. Note: arrays cannot be passed to child processes — see doc/sources.md $ define-alt EDITOR vim # set if unset No Test
define-alt-export Alias for define-alt --export; defines and exports variable if not defined $ define-alt-export EDITOR vim # export if unset No Test
force-unexport Unexports an environment variable $ force-unexport MY_VAR # remove env No Test
get-var Read and output the value of a variable by name $ get-var HOME # => /home/user Test
i-have Check if a specified command exists in the system $ i-have bat && echo yes # check cmd No Test
is-array Detect if a variable is an array (supports Bash and Zsh) $ is-array arr && echo yes # check array No Test
load-my-env Load environment-specific settings and aliases for various tools and runtimes $ load-my-env # load settings No Test
nvim-parent-edit Open files in parent Neovim instance via RPC from child terminal $ nvim-parent-edit file.txt # edit in parent No Test
source-if-exists Conditionally source a file if it exists $ source-if-exists ~/.local.sh # source if exists No Test

🔹 Recommended Scripts

Here are some scripts that can boost your daily workflow:

File Operations

rm-dust - Safe alternative to rm. Never lose files by accident again!

$ rm-dust important.txt        # Moves to dustbox instead of deleting
$ rm-dust *.log                # Clean up logs safely
$ alias rm=rm-dust             # Recommended: replace rm globally
$ rm-dust --restore            # Interactively restore files from dustbox

bak - Quick backup toggle. One command to backup, one to restore.

$ bak config.yaml              # Creates config.bak.yaml
$ vim config.yaml              # Edit the original
$ bak config.yaml              # Restore from backup if needed

nvim-parent-edit - Edit files in parent Neovim from nested terminal. (Show also an example: nvim.lua, keymaps.lua)

# Inside Neovim's :terminal
$ nvim-parent-edit file.txt   # Opens in parent Neovim, not a nested instance (not Neovim in Neovim)
$ nvim-parent-edit *.js       # Open multiple files

fast-sync - Efficient file sync by comparing file lists first.

$ fast-sync --init ~/photos    # Initialize sync state
$ fast-sync ~/photos /backup   # Only syncs new/changed files
# Much faster than full rsync for large directories
Testing

expects - Jest-like assertions for shell scripts. Write readable tests!

Many tests in this project (./test) are written with expects.

$ x=10 ; expects "$x" to_be 42
FAIL: expected {actual} to_be '42', but {actual} is '10'

$ x=42
$ expects "$x" to_be 42                          # No output on success (exit 0)
$ expects "$x" to_be 42 && echo "PASS"           # Equality check
PASS
$ expects "$x" not to_be 0 && echo "PASS"        # Negation
PASS
$ expects "hello world" to_contain "world"       # String containment

And more assertions are available. See expects.

Notifications & Timers

notify - Simple desktop notification. Works on macOS, Linux, and WSL.

$ notify "Build Done" "Your project compiled successfully"
$ make && notify "Success" "Build complete" || notify "Failed" "Build error"

notify-ntfy - Send notifications to your phone via ntfy.sh.

$ notify-ntfy "Backup Done" "Server backup completed"  # Sends to mobile
$ long-running-task && notify-ntfy "Done" "Task finished"
# Requires: export BASH_TOYS_NTFY_TOPIC="your-topic-name"
# See https://ntfy.sh for setup
# See ./bin/notify-ntfy for usage

notify-at - Schedule notifications with human-friendly time formats. (A wrapper for notify, and at command (Linux) or launchd (macOS).)

$ notify-at 15:00 "Meeting" "Team standup starting"         # Show notification to desktop at 3 PM
$ notify-at 15:00 "Meeting" "Team standup starting" --local # --local (Show notification to desktop) by default (Same as above)
$ notify-at "01-15 09:00" "Reminder" "Project deadline"     # Show notification to desktop on Jan 15 at 9 AM
$ notify-at 12:00 "Lunch" "Take a break" --mobile           # Send notification to mobile via ntfy.sh (if want to send both mobile and desktop, See below)
$ notify-at 18:00 "Dinner" "Cook" 1h --mobile --local       # Show/Send notification to both mobile and desktop

notify-cascade - Get reminded at multiple intervals before an event. (A wrapper for notify-at.)

$ notify-cascade 15:00 "Meeting" "Standup" 30m 10m 5m    # Show notification at 14:30, 14:50, and 14:55
$ notify-cascade 18:00 "Dinner" "Cook" 1h 30m --mobile   # Send notification to mobile (requires notify-ntfy setup)
$ notify-cascade 18:00 "Dinner" "Cook" 1h 30m --local    # Desktop only (default)
$ notify-cascade 18:00 "Dinner" "Cook" 1h --mobile --local  # Both mobile and desktop

pomodoro-timer - Simple Pomodoro technique timer with notifications.

$ pomodoro-timer              # Default 30 minutes
$ pomodoro-timer 25           # Classic 25-minute pomodoro
$ pomodoro-timer --rest 5     # 5-minute break timer
$ pomodoro-timer --from 09:30 60   # Resume timer that started at 09:30 for 60 minutes

pomodoro-cycle - Run a full multi-step Pomodoro cycle with breaks between sessions.

$ pomodoro-cycle              # 3 steps × 30 min (default)
$ pomodoro-cycle 3 25 25 25   # Classic 3 × 25 min pomodoro
$ pomodoro-cycle 2 45 30      # step 1: 45 min, step 2: 30 min
Text Processing

skip & slice - Simple but powerful text manipulation.

$ cat data.csv | skip 1                    # Skip header row
$ echo "a,b,c,d" | slice , 2 3             # Extract fields 2-3: "b,c"
$ ps aux | skip 1 | slice ' ' 1 2          # Get PID and user columns

take-until-empty - Read until blank line. Perfect for parsing sections.

$ cat changelog.md | take-until-empty          # Get first section only
$ git log --format="%B" -1 | take-until-empty  # Get commit title only

pathshorten - Shorten paths like Vim's pathshorten(). Great for prompts!

$ pathshorten ~/Documents/Projects/myapp/src  # => ~/Docu/Proj/myap/src
$ PS1="\$(pathshorten \$PWD) $ "              # Use in bash prompt
Navigation & Development

cd-finddir - Fuzzy directory navigation. Never type long paths again!

$ cd-finddir                  # Shows directory picker
...
luarrow.lua/src/
luarrow.lua/spec/
luarrow.lua/scripts/
luarrow.lua/luarrow.bak.lua/
luarrow.lua/doc/
luarrow.lua/
chotto.lua/src/
chotto.lua/spec/
chotto.lua/scripts/
chotto.lua/readme/
chotto.lua/doc/
chotto.lua/
...
> (Type partial name to filter, select to cd)

cd-to-git-root & git-root - Quick access to repository root.

$ cd-to-git-root              # Jump to repo root from anywhere
$ cat $(git-root)/README.md   # Reference files from repo root

cd-to-node-root - Jump to nearest package.json directory.

$ pwd
/project/src/components/ui
$ cd-to-node-root
$ pwd
/project                      # Jumped to package.json directory!
$ npm test                    # Now you can run npm commands

cat-which - Instantly view any script's source code.

$ cat-which rm-dust           # See how rm-dust works
$ cat-which my-script         # Debug your own scripts
Background Processes

start - Launch GUI apps without terminal noise.

$ start firefox               # Opens Firefox, returns prompt immediately
$ start code .                # Open VS Code without blocking
$ start vlc music.mp3         # Play music in background

kill-list - Interactive process killer. No more memorizing PIDs!

$ kill-list
  PID START                     COMMAND
...
12345 Thu Jan 30 10:15:00 2025  node server.js
12346 Thu Jan 30 10:15:01 2025  npm run watch
12347 Thu Jan 30 10:20:30 2025  python script.py
...
> Select process to kill (fuzzy search, multi-select with Tab)
Security

clamdscan-full - Full system virus scan with ClamAV.

$ clamdscan-full /            # Scan entire system
$ clamdscan-full ~/Downloads  # Scan specific directory
# Requires ClamAV daemon (clamd) running

📑 Show help for commands

Most commands support --help option:

$ rm-dust --help
rm-dust - Alternative to rm that moves files to dustbox instead of deletion

Usage:
  rm-dust FILE...
  rm-dust --help
...

If a command doesn't have --help, use bash-toys-help to extract help from script comments:

$ bash-toys-help rm-dust

# For 'source' commands (don't forget .sh extension)
$ bash-toys-help cd-to-git-root.sh

# Disable markdown rendering
$ bash-toys-help --disable-glow rm-dust

📑 Installation

In this section, we assumed you are using bash and ~/.bashrc. If you are using zsh, replace ~/.bashrc with ~/.zshrc.

🔹 Install all tools

  1. Clone the repository
$ git clone --depth 1 https://github.com/aiya000/bash-toys.git /path/to/bash-toys
  1. Source the source-all.sh script in your .bashrc or .zshrc
$ echo 'source /path/to/bash-toys/source-all.sh' >> ~/.bashrc
  1. (Optional) Enable bash completions
$ echo 'source /path/to/bash-toys/source-completions-all.sh' >> ~/.bashrc
  1. (Optional) Configure options if necessary
$ vim /path/to/bash-toys/define-options.sh

Or set in your .bashrc:

export BASH_TOYS_DUSTBOX_DIR="$HOME/dustbox"
export BASH_TOYS_MUSIC_PLAYER='afplay /System/Library/Sounds/Funk.aiff'
export BASH_TOYS_MUSIC_PLAYER_OPTIONS=''
Example configuration
export BASH_TOYS_INTERACTIVE_FILTER=fzf
export BASH_TOYS_DUSTBOX_DIR="$HOME/dustbox"
export BASH_TOYS_BATCAT_OPTIONS=''

🔹 Options

Please see ./define-options.sh and configure your options as needed.

🔹 Optional Dependencies

  • vlc: For pomodoro-start (if $BASH_TOYS_MUSIC_PLAYER is set to the default value)

🔹 Install each of the tools

Here is how to install individual tools.

  1. Create base directory
$ mkdir -p ~/lib/bash-toys || true
$ echo 'export PATH=$PATH:~/lib/bash-toys' >> ~/.bashrc
  1. (Optional) Install dependencies if needed
$ curl https://raw.githubusercontent.com/aiya000/bash-toys/refs/heads/main/lib/fun.sh -o ~/lib/bash-toys/fun.sh
$ echo 'source ~/lib/bash-toys/fun.sh' >> ~/.bashrc
  1. (Optional) Configure environment variables if necessary

Some scripts require environment variables to be configured. You can either:

Download and source define-options.sh:

$ curl https://raw.githubusercontent.com/aiya000/bash-toys/refs/heads/main/define-options.sh -o ~/lib/bash-toys/define-options.sh
$ echo 'source ~/lib/bash-toys/define-options.sh' >> ~/.bashrc

Or set the variables directly in your .bashrc (or .zshrc for zsh):

export BASH_TOYS_INTERACTIVE_FILTER=fzf
export BASH_TOYS_DUSTBOX_DIR="$HOME/dustbox"
export BASH_TOYS_BATCAT_OPTIONS=''
  1. Install a tool you want
$ curl https://raw.githubusercontent.com/aiya000/bash-toys/refs/heads/main/bin/bak -o ~/bin/bak

For ./sources/*, don't forget to source:

$ curl https://raw.githubusercontent.com/aiya000/bash-toys/refs/heads/main/sources/cd-to-git-root.sh -o /path/to/sources/cd-to-git-root.sh
$ echo 'source /path/to/sources/cd-to-git-root.sh' >> ~/.bashrc

📑 Contributing

We welcome contributions! Please follow these steps.

  1. Create an issue for the feature you want to add
  2. Wait for maintainers to approve the feature
  3. Open a pull request!

📑 License

This project is licensed under the MIT License - see the LICENSE file for details.


Happy scripting! 🐕

About

A tiny collection of shell script and aliases for bash/zsh for those who don't want to memorize too many.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Contributors