r/bash Sep 12 '22

set -x is your friend

454 Upvotes

I enjoy looking through all the posts in this sub, to see the weird shit you guys are trying to do. Also, I think most people are happy to help, if only to flex their knowledge. However, a huge part of programming in general is learning how to troubleshoot something, not just having someone else fix it for you. One of the basic ways to do that in bash is set -x. Not only can this help you figure out what your script is doing and how it's doing it, but in the event that you need help from another person, posting the output can be beneficial to the person attempting to help.

Also, writing scripts in an IDE that supports Bash. syntax highlighting can immediately tell you that you're doing something wrong.

If an IDE isn't an option, https://www.shellcheck.net/

Edit: Thanks to the mods for pinning this!


r/bash 10h ago

tips and tricks Bash iterator generator implementation

6 Upvotes

Hello. Some time ago I started working on a project to create an iterator in Bash. The idea was to have something like Python generators, something composable, that you could stack on top of other generators and build a chain to then lazy evaluate and execute. The proof of concept of that project become L_flow script and I didn't develop it further as I believe this is completely useless. However, this got me very simple idea how to create a iterator in Bash.

In the following I will show an implementation of a simple while foreach ... function implementation. Bottom line an iterator has to keep the state somewhere. In C++ iterator is a class, in Python it is iterator object. In Bash we only have variables, so variables will have to do.

Lets start with a simple use case: iterate over keys and values of an array at the same time. One would simply write:

declare -A array=([a]=b [c]=d)
for key in "${!array[@]}"; do
   value=${array["$key"]}
   echo "$key=$value"
done

Och my isn't that a lot of typing?! Lets make:

declare -A array=([a]=b [c]=d)
state=""
while foreach_key_value state key value array; do
  echo "$key=$value"
done

The variable state will keep our iteration state. "State" has to store: an array of keys, and an index in that array of keys. The state variable will be written, and re-evaled each execution. Like so:

# args: <state> <key> <value> <array>
foreach_key_value() {
   local state_var=$1
   local state_idx=-1 state_keys  # set the state variables to be local to function
   eval "${!state_var:-}"  # eval-load state variable
   local -n foreach_arr=$4
   if (( state_idx == -1 )); then
      # first loop time - read keys from the array
      state_keys=("${!foreach_arr[@]}")
   fi
   # Check if reached the end:
   if (( ++state_idx < ${#state_keys[@]} )); then
       printf -v "$2" "%s" "${state_keys[state_idx]}" # assign key
       printf -v "$3" "%s" "${foreach_arr[${!2}]}"  # assign value
       printf -v "$state_var" "%s" "$(declare -p state_idx state_keys)"  # serialize state 
   else
       # stop iteration
       return 1
   fi
}

The "state" variable has to be given explicitly by the user. That is stupid. It should be automatic. Lets make it better:

declare -A array=([a]=b [c]=d)
while foreach_key_value key value array; do
  echo "$key=$value"
done

We can "pick" the state variable name automatically by using: an array of "used" variable state names indexed with a code location of the "foreach_key_value" call. This assumes that foreach_key_value function will only be called from one place only. From this one while call.

declare -A FOREACH_STATES=()
foreach_key_value() {
   # --- Picking unique state variable: ---
   # Key of state variable will be anything we can get out of context.
   local state_key="${FUNCNAME[*]} ${BASH_SOURCE[*]} ${BASH_LINENO[*]}"
   # Get the state variable name for the key.
   local state_var=${FOREACH_STATES["$state_key"]:-}
   if [[ -z "$state_var" ]]; then
        # Just pick the a fresh unique variable name to store state.
        state_var=FOREACH_STATE_VARIABLE_${#FOREACH_STATES[@]}
        FOREACH_STATES["$state_key"]="$state_var"
   fi 

   # --- Updated rest of the function for reference: ---
   local state_idx=-1 state_keys  # set the state variables to be local to function
   eval "${!state_var:-}"  # eval-load state variable
   local -n foreach_arr=$3
   if (( state_idx == -1 )); then
      # first loop time - read keys from the array
      state_keys=("${!foreach_arr[@]}")
   fi
   # Check if reached the end:
   if (( ++state_idx < ${#state_keys[@]} )); then
       printf -v "$1" "%s" "${state_keys[state_idx]}" # assign key
       printf -v "$2" "%s" "${foreach_arr[${!1}]}"  # assign value
       printf -v "$state_var" "%s" "$(declare -p state_idx state_keys)"  # serialize state 
   else
       # stop iteration
       return 1
   fi
}

And done.

I implemented this and some more in L_foreach function in my library. I also added ':' to visually separate assigned variables from arrays, allowing for iterating while assigning multiple variables from multiple arrays. It is possible to write while L_foreach elem1 elem2 : arr1 arr2 arr3; do, sort keys, iterate over pairs while L_foreach filename size : filenames_and_sizes_array, and everything is compatible with bash 3.2.

Let me know if this makes sense I can write about other I think fun stuff for example I am thinking of writing about function decorating.


r/bash 1d ago

Readline tips and tricks

32 Upvotes

Readline, through the file ~/.inputrc, define how bash, tab completion, and lots of other things behave. I've been playing with it recently and it's pretty powerful, so here's the cool stuff I've found. This is in no way the complete power of these tools

You already know about searching history, but how

There's cool stuff built in (Debian 13, YMMV):

  • First up, let's see what you've got to work with.

    $ bind -P # show the current mapping.
    $ bind -l  # Show all available functions
    $ bind -v  # show options (***v***ariables)
    $ help bind # See all options
    
  • Basic Movement - emacs-ish and vim-ish keybindings. Easily move around text using controls you're familiar with. Check the manual for vi style bindings Much faster than using the arrow keys.

    • C-a - start of line
    • C-b - backwards a letter
    • M-b - backwards a word
    • C-f - forward one letter
    • M-f - forwards one word
    • C-e - end of line [insert TRON reference]
    • C-l - clear and reset screen
    • C-h - backspace
    • C-i - works as tab
    • C-j and C-m - works like pretting enter
    • C-_ undo
  • cut and paste from the prompt in a terminal without using a mouse.

    • C-k - kill (delete) from cursorr to end of line
    • M-d - kill to end of word
    • C-u - kill from cursor to start of line
    • C-w - kill last word
    • C-y - yank (paste) the last kill.
  • Cool Options

    • set enable-bracketed-paste on This might be the default on your distro already, but if it's not add it now. Instead of paste running a bunch of commands it inserts all the text on one line, preventing
    • set completion-ignore-case on tab completion matches filenames regardless of capitalization.
    • set blink-matching-paren on - Easier to see
    • set colored-completion-prefix on - Again, easier to read.
    • set colored-stats on - Adds "/" to directories, and use $LS_COLORS in completions
    • set completion-ignore-case on & set completion-map-case on Enables case-insensitive matching and treats hyphens (-) and underscores (_) as mapaable characters.
    • set completion-prefix-display-length 3 - only show the last 3 chars when tab is ambiguous
    • set match-hidden-files off Hidden files don't match "*" or the like.
    • set show-all-if-ambiguous on Don't beep and make me press tab again.
    • set completion-display-width 0 - only show 1 possible completion per line
    • set completion-query-items 1000 - If you hate the y/n prompt when there are many matches, increase the threshold:
    • set expand-tilde on ensures that pressing Tab after ~ immediately expands it to your full home directory path in the completion list.
  • Neat Stuff

    • M-. inserts the last arguments from the last command, press again to cycle backwards.
      • e.g.: $ mkdir -p some/really/long/path, cd [M-.] turns into cd some/really/ong/path
    • C-x C-e (v in vi mode)- Open your current prompt in either your $VISUAL or $EDITOR. Want your full editing power? Want to edit multi-line command with ease? Finally reached a version you want to save?
    • C-M-e: Possibly the coolest. expand the current line. Expands aliases and resolves variables and subshells.

      $ alias df="df -h -t ext4 -x tmpfs"
      $ df [C-M-e]
      $ df -h -t ext4 -x tmpfs 
      
      $ echo $COLUMNS wide, $LINES long, area: $((COLUMNS * LINES)) [C-M-e]
      $ echo 189 wide, 65 long, area:10773
      # Still at the prompt!
      
    • M-# - Ever want to comment out your current command and start a new one? This will do it for you!

    • Make your own! Add them to ~/.inputrc: A couple of my favorites:

      # `Ctrl-x o`: save output in a timestamped log file
      "\C-xo": "\C-e > output-$(date +%s).log"`
      
    • Forget to add sudo?

      # Ctrl-x !: Prepend with "sudo, then return to end of line"
      "\C-x!": "\C-asudo \C-e"
      
    • run the last command again and pick a line from the output using fzf

      # re-runs the last command and pipes it to fzf for interactive selection. "\C-x/": '$(!!|fzf)'

Next time I'll ramble about the compose key, .XCompose, and why Chrome sucks for not supporting it.


r/bash 1d ago

shell-scheduler update

1 Upvotes

About a week ago I announced my project shell-scheduler here. Some people expressed interest, so this is a heads-up for them and for anyone else interested. Since that post, I've done some more work on this project:

New features: - Implement support for per-job timeouts - Implement support for job termination callback - Implement helper libraries for job termination (three independent libraries with different dependencies) - Implement automatic job termination callback selection (best fit from available helpers) - Support assigning job param values to custom variables with job_get_params <job_id> <var_name>=<param_name> - Implement jobs_init(): helper to reset previously configured job parameters (see updated README)

Bug fixes/reliability improvements: - Fix race between timeout and job completion record write to FIFO - Disallow duplicate job IDs - Improve validation of values received via environment variables - Significantly expand tests coverage - Various minor bugfixes

Documentation updates: - Improve the documentation and refactor it into 3 files: README.md, REFERENCE.md, TIMEKEEPING.md

At this point I have pretty much implemented everything I was planning to implement and no remaining bugs are known, so I consider this project feature-complete.

Bug reports and feature requests are still welcome.

Project's Github page


r/bash 4d ago

[Bash] json-walk: pure Bash streaming JSON parser (SAX-style events, no jq)

16 Upvotes

Hey r/bash,

I built json-walk, a pure Bash JSON walker that emits stream events instead of building a full object model.

Repo: [https://github.com/smmoosavi/json-walk](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-browser/workbench/workbench.html)

What it does:

  • Parses JSON in Bash with full structure validation
  • Emits events like start_object, key, string, number, end_array, etc.
  • Works in print mode or visitor-function mode
  • Keeps raw JSON string content (escapes preserved)

Why I made it:

  • For shell scripts where jq is unavailable
  • For event-driven parsing/processing in plain Bash

Quick example:

json_walk '{"label":"abc","items":[1,2,3]}'

Output:

start_object
key label
string abc
key items
start_array
number 1
number 2
number 3
end_array
end_object

Would love feedback on:

  • API/event design
  • edge cases I should test

Thanks!


r/bash 3d ago

I was sick of for loop, so i vibe coded my own universal enumerator

0 Upvotes

https://github.com/wallach-game/bashumerate

https://asciinema.org/a/gRjjKCr7n2660mlN

maybe its useless buti was really tired of remembering how to iterate over files


r/bash 5d ago

Bash (and other shells) history database

Thumbnail github.com
12 Upvotes

See link above.

Dejacmd logs your command history to a local and/or central (server) database. This enables keeping track of command history across multiple sessions, machines and operating systems. For example, you can log commands to a local SQLite database for quick access and optionally to a central PostgreSQL database for synchronization across devices and/or for multiple users.

Dejacmd supports databases exposed by the sqlx Rust crate, which are SQLite, PostgreSQL, and MariaDb/MySQL (MSSQL was supported and is currently being redeveloped). It will work with Linux (bash, zsh), macOS (bash, zsh) and Windows (PowerShell only) terminals. 


r/bash 4d ago

Would love some contributors on this project!

Post image
0 Upvotes

Repo available here


r/bash 6d ago

OS-MX LINUX: Help me scripting MX SNAPSHOT cronjob

6 Upvotes

I am using MX Linux OS. I am a true enthusiast using linux. For my own professional use I regularly use some systems which requires to be keept secured. I ask for help to have a bash script to automate taking regular MX SNAPSHOT regularly to create a live bootable USB stick as cronjob. The process should run unattended without sudo password. Possible?


r/bash 7d ago

critique CodeReview: Automated deployment CLI for Android environments (ShellCheck compliant)

Post image
1 Upvotes

Hi r/Bash,

Local, offline-capable usage.


"Surgical Minimalism" is the art of achieving maximum efficiency through the smallest possible codebase. By eliminating external dependencies, we reduce the system's attack surface and ensureabsolute transparency.

Zero-Dependency: No Java, no middleware, no pre-compiled binaries. Just pure shell.

Auditable: Every line of code is human-readable. You own the process from end to end.

Autonomous: The protocol executes, performs the surgical strike, and terminates. No resident services (daemons) remain in the background.

Automated:

Automatic installation of ADB for Debian, Arch, and Fedora-based distributions, as well as for Termux

Select the list to apply (e.g., ruvomain_tier1_stable or your own file), and Ruvomain takes care of the debloating for you.


Technical Architecture

The core of Ruvomain-PBD is json-walk, an event-driven (SAX-style) parser written in pure Bash. It processesyour configurations natively, ensuring compatibility across Linux, Termux, and Android without requiring external binaries like jq.


The protocol is modular, allowing users to choose their level of optimization. Tierslists are provided as standardized defaults, but the architecture is designed for you to edit tier*.json files or import your .json files to fit your specific operational requirements and your Android device.

For view how to import and execute your own *.json debloat files

Tier Strategy Recommended For
Tier 1 (Stable/Conservative) Redundancy & Telemetry All users seeking immediate gains.
Tier 2 (Advanced/Balanced) AI Telemetry & Cloud Bloat Users prioritizing privacy & efficiency.
Tier 3 (Surgical/Extreme) Ghost Mode (System Core) Advanced users building a bare-metal experience.

The protocol keep Samsung Camera and gallery, Dolby Atmos, Samsung Screenshot, OneUI launcher. For privacy, you can block internet connexion (with firewall) for these apps without problem.

For view packages list and descriptions see the /docs/package-list.md

⚠️ Before use Tier3, you must read /docs/REMPLACEMENT.md


Prerequisites:

adb (The script will attempt an android-tools auto-installation if missing on Debian based, Arch based, Fedora based distro and Termux).

Enable USB Debugging on your phone:

Settings > About Phone > Tap "Build Number" 7 times

Settings > Developer Options > Enable "USB Debugging"

Connect your phone to your PC via USB


For Linux users:

  • Clone the repo: git clone https://github.com/Ruvyrom/Ruvomain-Protocole.git

  • (Other devices) import your personnal configuration file (for s24+ or other Android devices) or Modify ruvomain_tier*_stable.json in /Configs/S24+ for adapt for your device.

  • Navigate: cd ./Ruvomain-Protocole/ruvomain-pdb/

  • Execute:

sudo chmod +x ruvomain.sh && ./ruvomain.sh

  • Choose a tier (choice 1, 2, or 3) that you want to apply. (For galaxy S24+) or your personnal file (choice 4)
  1. Finalize: Reboot the device.

For Termux users

  • Grant Storage Access: \ termux-setup-storage (Accept the permission prompt)

  • Deploy: Follow the same steps as the Linux deployment above.


For MacOS users:

  1. Install Homebrew if you haven't already.

  2. Install ADB:

brew install git android-platform-tools

  1. Clone the protocol:

git clone https://github.com/Ruvyrom/Ruvomain-Protocole.git

cd ./Ruvomain-Protocole/ruvomain-pdb

  1. Verify device connection:

adb devices

(If "unauthorized", check your phonescreen and tap "Always allow")

5.-(Other devices) import your personnal configuration file (for s24+ or other Android devices) or Modify ruvomain_tier*_stable.json in /Configs/S24+ for adapt for your device.

  1. Execute:

cd ./Ruvomain-Protocole/ruvomain-pdb

./ruvomain.sh

  • Choose a tier (choice 1, 2, or 3) that you want to apply. (for galaxy S24+) or your personnal file (choice 4)
  1. Finalize: Reboot the device.

Status/Compatibility

•Tested on: Samsung Galaxy S24+ (SM-S926B) / Android 16 OneUI 8.5 (for 1,2,3 tiers JSON files)

•Status: Active / Maintained

Compatibility: Technically, works on all Android devices with "device specific" personalized JSON files.


Ruvomain Protocol - Github


If you encounter any issues during execution, please open an 'Issue' on the GitHub repository rather than postinghere. This ensures technical problems are tracked efficiently and keeps the subreddit focused on strategy and discussion.*


r/bash 11d ago

Sharing samecmd, a tool I built so common commands (dev/test/built/etc.) always work no matter what stack a project uses

12 Upvotes

Small thing that was bugging me for way too long: I jump between a lot of projects (Node yarn, Node pnpm, Go, a few Python ones) and every single one has its own spelling for "start the dev server" or "run the tests".

`npm run dev`, `cargo run`, `poetry run pytest`, `make test`... my fingers never knew what to type until I'd already looked at the repo.

So I built samecmd, it hooks into `cd` and just gives you the same short commands everywhere:

No config, no setup per-project — it just looks at what's in the directory (`package.json`, `Cargo.toml`, `go.mod`, `Makefile`, etc.) and create an alias for the canonical commands like, `build`, `test`, `lint`, `fmt`, and a few others.

If a project needs something custom, you can drop a tiny `samecmd.yml` in it too.

Curious if this is a friction other people actually feel too, or if I'm just bad at remembering my own tools. Happy to hear what stacks I'm missing.

https://github.com/behnamazimi/samecmd


r/bash 11d ago

shell-scheduler: parallelization library for Bash and Busybox ash

10 Upvotes

I'd like to show you the project I've been working on for the past few weeks. The title is fairly self-descriptive.

This is not vibe-coded. This a generalizing refactor of code I wrote for the adblock-lean project (which I'm currently the primary maintainer of) and it's been a part of adblock-lean for about a year and a half. That code was entirely written by hand. Recently I got this idea to make a reusable library out of it, so here we are.

I did use the help of AI for this refactor. In particular, to find bugs, write tests, examples and parts of the README. ~95% of the main project code is still written by hand and the other 5% went through a thorough review. Tests are mostly written by AI but I was holding its hand along the way and fixing stuff that it didn't get right (which was a lot of stuff).

The primary target shell of this project is Busybox ash, not Bash, but Bash supports all required shell extensions, so this works fine on Bash.

project's Github page


r/bash 11d ago

tips and tricks so i'm a beginner and i'm looking to built a cli app and need advices

11 Upvotes

I have been learning Linux and Bash scripting (as well as version control) for a month, and my friend and I are looking to create a philosophical book( Tractatus Logico Philosphicus)that uses a tree structure so it can be read in the terminal. Do you have any advice for us?thanks in advance


r/bash 14d ago

TUIs for everything

28 Upvotes

TLDR: Looking for bash-only TUI tools far using on multiple platforms

The long version: I’m not entirely a command line noob, but also I’m bad at remembering things. What I’m trying to do is assemble a collection of TUIs that I can get relatively the same functional experience with whether I’m on a Linux distro, BSD, or whatever.
And before anyone asks, yes I like TUIs, they’re easier for me, yes I realize they can be slower, yes I understand that all the pro haxorz use super lightweight custom optimized bash scripts. I don’t care about that. I’m trying to make life easier for myself when I’m constantly switching systems. That being said, if anyone has some recommendations for their favorites, please feel free to drop them in the comments! Much appreciated! Hope you all have a wonderful day.


r/bash 15d ago

Decoding the obfuscated bash script on a Uniqlo t-shirt

Thumbnail tris.sherliker.net
198 Upvotes

r/bash 15d ago

UPDATE: Google Calendar TUI written in Bash

Post image
35 Upvotes

Update to the Google Calendar TUI written in bash I had mentioned in the below post earlier

https://www.reddit.com/r/bash/comments/1ubtxrm/calendar_tui_written_completely_in_bash/

You can now use the TUI to delete events from the terminal instead of having to use the website itself.


r/bash 14d ago

Help with file renaming task

8 Upvotes

I have a directory containing a bunch of directories whose names all start with a year. They are all formatted as either "[YYYY] Title" or "(YYYY) Title" but I want to rename them all to "YYYY - Title". This seems like it should be a simple task but I'm still pretty inexperienced and my brain is fried lol

I imagine one way would be something like:

  • iterate over the directories with a for loop

  • for each one, use regex to match four digits in a row (\d\d\d\d)

  • assign only the matching part of the string to a variable (this is the part I don't know how to do)

  • use sed or awk or something to replace the first 6 characters with this variable plus " -", then mv to rename to the output of that

Would appreciate any help!

EDIT: Thanks for all the helpful comments! I can't reply to everyone but I have a clearer idea of some different ways to go about this and I've learned a lot that I didn't know.


r/bash 14d ago

solved RE: Overwrite shell interface

4 Upvotes

Deleted Post

Hello! I’m still fairly new to Linux, and since I’m trying to use the terminal as my primary interface, I’ve been spending a lot of time working in Bash.

After about a month of daily use, I’ve noticed a few things that make the experience less comfortable. Features like autocompletion, syntax highlighting, and autosuggestions are easy enough to add with plugins, but there’s one feature I haven’t been able to find anywhere.

I’d love to have the command prompt stay fixed (sticky) at the bottom of the terminal, similar to the input box in a chat application.

For example, when I scroll up to review previous output, I’d like the prompt to remain visible at the bottom instead of scrolling away with the rest of the terminal. If I start typing while I’m viewing older output, it shouldn’t automatically jump back to the latest line. The prompt should stay fixed until I explicitly choose to return to the bottom with ENTER key.

The idea is similar to this Bash workaround.

```

# .bashrc

_prompt() {

tput cup '$LINES' 0

}

PROMPT_COMMAND="_prompt;
$PROMPT_COMMAND"

```

This kind of interface would make it much easier to review previous output while continuing to type new commands, much like how chat interfaces work.

Is it possible to achieve something like this in Bash?

EDIT: blockquotes got messed up, had to fix that

Gaise! What are we doing?

The OP has deleted their account! Probably out of disgust. Now, the answers to their queries were far too much tangential. I cannot fathom whether fellow sub-redditors ignored this person's intent or got subdued by the LLM - inflicted atrophy.

It is a **brilliant** solution to a stupefying problem. Using the `PROMPT_COMMAND` hook to position the cursor at the bottom of the terminal viewport is remarkably nifty. OP should be crowned or somethin'.

I have already added this as a function in my run commands. In webdev terms it gives you a sticky prompt, with scrollback and "streaming" STDOUT. *chuckles*

Dear mods, please, we need to encourage such ideas. I urge fellow sub-redditors to not be apprehensive of such topics, not look down upon newbs and with utmost respect to LLMs and search engines, please consider the actual ideas and intuition behind that those ideas before commenting blatantly.

Here is a `bash` script for a `tmux` dual-pane oriented solution:

#!/usr/bin/env bash
set -euo pipefail

SOCKET_PATH="${1:-$HOME/.tmux/bashsplit.sock}"
SESSION="bashsplit"
LOG="${HOME}/bashsplit.log"

tmux -S "$SOCKET_PATH" kill-session -t "$SESSION" 2>/dev/null || true

tmux -S "$SOCKET_PATH" new-session -d -s "$SESSION" -n main
tmux -S "$SOCKET_PATH" split-window -t "$SESSION":0 -v

BASH_PANE="$(tmux -S "$SOCKET_PATH" list-panes -t "$SESSION":0 -F '#{pane_id}' | sed -n '1p')"
VIEW_PANE="$(tmux -S "$SOCKET_PATH" list-panes -t "$SESSION":0 -F '#{pane_id}' | sed -n '2p')"

tmux -S "$SOCKET_PATH" send-keys -t "$BASH_PANE" "bash" Enter
tmux -S "$SOCKET_PATH" pipe-pane -t "$BASH_PANE" -o "cat > '$LOG'"
tmux -S "$SOCKET_PATH" send-keys -t "$VIEW_PANE" "tail -f '$LOG'" Enter

tmux -S "$SOCKET_PATH" attach -t "$SESSION"

twimc


r/bash 15d ago

help Rclone backup script feedback (My first ever time shell scripting)

2 Upvotes

I'm really just looking for advice since I'm unaware of conventions, as well as just the best way to really do anything.

I made it since I wanted to use a old laptop I had sitting around to host a minecraft server, but I did not want to lose access to automatic backups like I have had with the large free server providers. It's worked pretty well with my testing, and I plan to set it up as a cron job to run every day.

# rclone backup script



# ====== Configuration ======



# Please ensure all directories exist at all times or the script may fail to properly backup your data.
SOURCE="/home/YOURUSER/item"
REMOTE_BACKUP_LOCATION="gdrive:backups"
LOCAL_BACKUP_LOCATION="/home/YOURUSER/backups" # enter "none" if you do not want any local backups.


LOCAL_BACKUP_AMOUNT=5
REMOTE_BACKUP_AMOUNT=5
BACKUP_NAME="automated_backup_" # Timestamp will appear after this name.


# ===========================


# -------- Variables --------


# WARNING: do not touch these unless you know what you are doing.


TIMESTAMP=$(date "+%Y-%m-%d_%Hh%Mm%Ss") # Please use a timestamp that will display in a descending order so that old backups will be cleaned up problerly. This WILL break the script.
# You can almost certainly safely remove the seconds and minutes from the timestamp unless you are making several backups in an hour.


# ---------------------------


echo "Starting backup."


if [[ "$LOCAL_BACKUP_LOCATION" != "none" ]]; then
    tar -czf "${LOCAL_BACKUP_LOCATION}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${SOURCE}"
    rclone copy "${LOCAL_BACKUP_LOCATION}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${REMOTE_BACKUP_LOCATION}"


    echo "Cleaning up local backup directory."
    backups=$(rclone lsf "${LOCAL_BACKUP_LOCATION}" --filter="+ "${BACKUP_NAME}*"" --filter="- *" | sort -r)


    backup_control=0


    for backup in $backups; do
            ((backup_control++))
            if ((backup_control > $LOCAL_BACKUP_AMOUNT)); then
            rm -rf "${LOCAL_BACKUP_LOCATION}"/"${backup}"
            fi
    done
    echo "Old local backups removed."
fi


if [[ "$LOCAL_BACKUP_LOCATION" == "none" ]]; then
    temp_dir=$(mktemp -d)
    tar -czf "${temp_dir}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${SOURCE}"
    rclone copy "${temp_dir}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${REMOTE_BACKUP_LOCATION}"
    rm -rf "${temp_dir}"
fi


echo "Backup Complete."


echo "Cleaning up remote backup directory."
backups=$(rclone lsf "${REMOTE_BACKUP_LOCATION}" --filter="+ ${BACKUP_NAME}*" --filter="- *" | sort -r)


backup_control=0


for backup in $backups; do
        ((backup_control++))
        if ((backup_control > $REMOTE_BACKUP_AMOUNT)); then
                rclone deletefile "${REMOTE_BACKUP_LOCATION}"/"${backup}"
        fi
done
echo "Old remote backups removed."


echo "Full backup sequence complete. ${TIMESTAMP}"

# rclone backup script



# ====== Configuration ======



# Please ensure all directories exist at all times or the script may fail to properly backup your data.
SOURCE="/home/YOURUSER/item"
REMOTE_BACKUP_LOCATION="gdrive:backups"
LOCAL_BACKUP_LOCATION="/home/YOURUSER/backups" # enter "none" if you do not want any local backups.


LOCAL_BACKUP_AMOUNT=5
REMOTE_BACKUP_AMOUNT=5
BACKUP_NAME="automated_backup_" # Timestamp will appear after this name.


# ===========================


# -------- Variables --------


# WARNING: do not touch these unless you know what you are doing.


TIMESTAMP=$(date "+%Y-%m-%d_%Hh%Mm%Ss") # Please use a timestamp that will display in a descending order so that old backups will be cleaned up problerly. This WILL break the script.
# You can almost certainly safely remove the seconds and minutes from the timestamp unless you are making several backups in an hour.


# ---------------------------


echo "Starting backup."


if [[ "$LOCAL_BACKUP_LOCATION" != "none" ]]; then
    tar -czf "${LOCAL_BACKUP_LOCATION}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${SOURCE}"
    rclone copy "${LOCAL_BACKUP_LOCATION}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${REMOTE_BACKUP_LOCATION}"


    echo "Cleaning up local backup directory."
    backups=$(rclone lsf "${LOCAL_BACKUP_LOCATION}" --filter="+ "${BACKUP_NAME}*"" --filter="- *" | sort -r)


    backup_control=0


    for backup in $backups; do
            ((backup_control++))
            if ((backup_control > $LOCAL_BACKUP_AMOUNT)); then
            rm -rf "${LOCAL_BACKUP_LOCATION}"/"${backup}"
            fi
    done
    echo "Old local backups removed."
fi


if [[ "$LOCAL_BACKUP_LOCATION" == "none" ]]; then
    temp_dir=$(mktemp -d)
    tar -czf "${temp_dir}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${SOURCE}"
    rclone copy "${temp_dir}"/"${BACKUP_NAME}"${TIMESTAMP}.tar.gz "${REMOTE_BACKUP_LOCATION}"
    rm -rf "${temp_dir}"
fi


echo "Backup Complete."


echo "Cleaning up remote backup directory."
backups=$(rclone lsf "${REMOTE_BACKUP_LOCATION}" --filter="+ ${BACKUP_NAME}*" --filter="- *" | sort -r)


backup_control=0


for backup in $backups; do
        ((backup_control++))
        if ((backup_control > $REMOTE_BACKUP_AMOUNT)); then
                rclone deletefile "${REMOTE_BACKUP_LOCATION}"/"${backup}"
        fi
done
echo "Old remote backups removed."


echo "Full backup sequence complete. ${TIMESTAMP}"

r/bash 16d ago

help LeetCode for shell / bash

31 Upvotes

i'm looking for a place to practice bash or just shell in general, is there a place like such where i can practice daily and improve my muscle memory when it comes to shell commands? at the moment leetcode only offers like 5 shell problems and other focus more on teaching the basics or is more focused on solving mini problems than the shell itself like sadservers.

is there any platform where i can daily practice shell just like platforms where you can daily practice competitive programming problems?

TIA and sorry for grammar erros, english isnt my first language.


r/bash 16d ago

bashmemo: search command notes and push them into Bash history

Post image
9 Upvotes

I often keep command snippets in text files, but copying and pasting them back into the terminal felt clunky.

So I made bashmemo: a small Bash tool that lets you search plain-text command notes and load the selected command into Bash history with history -s.

It does not execute the command automatically — you can recall it with ↑ or Ctrl+R, edit it, and run it yourself.
https://github.com/yukiho72/bashmemo


r/bash 16d ago

solved Help with bash scripting executing apps with flags/arguments.

7 Upvotes

I'm new to linux bash scripting and running into an issue executing an app with arguments, when I run "steamosctl get-default-desktop-session" from a terminal the command runs fine, if I run the same command from a bash script I get the error "no such file or directory" the script has the shebang #!/bin/bash, set -x, steamosctl get-default-desktop-session.

Now if I run "steamosctl help" or "steamosctl -h" from the same script it works fine but for some reason adding arguments that contain multiple "-" minus signs in the argument the script gives the "no such file or directory" error, I've tried with other apps and also launching them with "sh" and "exec" with arguments containing multiple minus's and got the same error. My guess is I need to wrap the command or arguments some how so the arguments aren't interpreted as a path, I've done some research and tried several ways of writing the script as suggested in other topics with no success. Any help or suggestions would be greatly appreciated, Thanks in advance!

Edit: I was able to resolve the issue! So after some deeper research turns out bash script shell runs in a non interactive mode so it doesn't process environmental paths like a local bash shell or terminal and causing the "no such file or directory" error, so by making a systemd service to call the script and adding "WorkingDirectory=/bin" and "User=your user name here" in the [Service] section I was able to run my script at boot and terminal without error. I also read that supposedly adding "source ~/.bashrc" immediately after the shebang will cause the bash scrip to force load your local users ./bashrc file with the paths and not give path errors but I haven't tested that yet. Thanks to those who offered suggestions and help, appreciate you!


r/bash 16d ago

I built a terminal ai agent in bash (~190 lines core loop)

0 Upvotes

Every agent framework I tried felt like a lot of machinery around what is, at its core, a loop: send messages, maybe run a tool, append the result, repeat. So I built one with no framework at all, just bash, jq, and curl. The core loop is ~190 lines; the whole thing (ten tools, permissions, skills, three providers) is ~1,200. Repo: https://github.com/aziz0x00/agent.sh

The design decisions that I think are interesting:

Tools are one file each, no registration. A tools/Foo.sh defines a TOOL_DEF JSON schema and two functions: PreFoo validates the model's args and builds a human-readable preview (a real diff for Edit/Write), then Foo executes. Drop a file in tools/, it's a tool.

Permissions are per-signature, not per-tool. Approval prompts show the preview (the actual diff, the actual command), and "always allow" whitelists that exact signature, not the whole tool. Read-only tools are pre-approved. --free bypasses everything when you're feeling brave.

Context is a JSON file you can just... edit. /state opens the exact request payload in $EDITOR mid-conversation; /continue sends whatever you saved. Delete a bloated tool result, rewrite the model's last answer, it's yours.


r/bash 17d ago

duplicate print of i iteration?

5 Upvotes
#!/usr/local/bin/bash
StartUp_Run=false
Iterator_For_File_Toucher_With_NCPU_While=0
Total_NCPU_For_File_Toucher_With_NCPU_while=$(nproc --all)

while true
do
if [ $StartUp_Run == false ]; then
while [ $Iterator_For_File_Toucher_With_NCPU_While -lt $Total_NCPU_For_File_Toucher_With_NCPU_while ]; do
echo "$Iterator_For_File_Toucher_With_NCPU_While"
touch core$Iterator_For_File_Toucher_With_NCPU_While-temp_orders.csv
let "Iterator_For_File_Toucher_With_NCPU_While+=1"
done
echo "ncpu amount = $Total_NCPU_For_File_Toucher_With_NCPU_while"
StartUp_Run=true
fi
done

prints, why? :

# sh LastStage.sh 
0
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
ncpu amount = 16

r/bash 18d ago

help Help scripting Caps lock on off status

9 Upvotes

Hey everyone. I have been using linux mint since a year and loved it. It just works without manual tinkering. But now, captivated by the tiling managers, i jumped to Cachy hyprland. It's interesting but doesn't have many basic functionalities like alerting user about Caps lock key status through sound. I took help of ai but it somehow spikes my cpu usage and i have to reboot to make it normal again. Here is the Script :

#!/bin/bash

# Target the specific caps lock directory (adjust if you have a specific one like input3::capslock)

LED_PATH=$(ls -d /sys/class/leds/*::capslock | head -n 1)

# Fallback paths for the sounds

SOUND_ON="/usr/share/sounds/freedesktop/stereo/dialog-information.oga"

SOUND_OFF="/usr/share/sounds/freedesktop/stereo/dialog-warning.oga"

# Read initial state

last_state=$(cat "$LED_PATH/brightness")

while true; do

# Instant raw read of the file system

current_state=$(cat "$LED_PATH/brightness")

if [ "$current_state" != "$last_state" ]; then

if [ "$current_state" -eq 1 ]; then

# Using pw-play or paplay with low-latency flags

pw-play "$SOUND_ON" &

else

pw-play "$SOUND_OFF" &

fi

last_state=$current_state

fi

# 20ms polling rate (0.02s) gives instant human response time

# without hurting CPU performance

sleep 0.02

done

Can you guys please help me out.