Is this a good image compression method
I want to create a noscript that performs image compression with the following rules and jpegoptim:
1. Limit the maximum height/width to 2560 pixels by proportional scaling.
2. Limit the file size to scaled (height width 0.15) bytes.
Is this plausible?
https://redd.it/1ovaze0
@r_bash
I want to create a noscript that performs image compression with the following rules and jpegoptim:
1. Limit the maximum height/width to 2560 pixels by proportional scaling.
2. Limit the file size to scaled (height width 0.15) bytes.
Is this plausible?
https://redd.it/1ovaze0
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
Wayland Backlight LED solution help
github with the noscripts: https://github.com/somniasum/wayland-backlight-led
Hey guys so after switching from Xorg to Wayland, like aeons ago, I noticed there isn't support for keyboard backlight LED on Wayland yet.
Unlike on Xorg you could use 'xset led' for all that but guess that doesn't work on Wayland cause of like permissions and stuff? IDK.
Anyway I made some sort of solution for the LED stuff and it works just barely.
Reason being when pressing CAPS LOCK the LED turns off and stuff and isn't really persistent and stuff. So hopefully you guys can help with finding a better solution that's more persistent with the LED state.
Thanks in advance.
https://redd.it/1ovc65y
@r_bash
github with the noscripts: https://github.com/somniasum/wayland-backlight-led
Hey guys so after switching from Xorg to Wayland, like aeons ago, I noticed there isn't support for keyboard backlight LED on Wayland yet.
Unlike on Xorg you could use 'xset led' for all that but guess that doesn't work on Wayland cause of like permissions and stuff? IDK.
Anyway I made some sort of solution for the LED stuff and it works just barely.
Reason being when pressing CAPS LOCK the LED turns off and stuff and isn't really persistent and stuff. So hopefully you guys can help with finding a better solution that's more persistent with the LED state.
Thanks in advance.
https://redd.it/1ovc65y
@r_bash
GitHub
GitHub - somniasum/wayland-backlight-led: An alternative to 'xset' in Wayland for keyboard backlight LED
An alternative to 'xset' in Wayland for keyboard backlight LED - somniasum/wayland-backlight-led
where to correctly set PATH
I ran into a problem where a GUI program can't run a command because it can't find it. I realized it's because I only modify PATH inside .bashrc, so of course a program not started by bash would only see the default PATH.
where should I update PATH?
P.S. the default .profile already sources .bashrc but is somehow not exporting the variables? (otherwise I wouldn't have this problem)
https://redd.it/1ovfib3
@r_bash
I ran into a problem where a GUI program can't run a command because it can't find it. I realized it's because I only modify PATH inside .bashrc, so of course a program not started by bash would only see the default PATH.
where should I update PATH?
P.S. the default .profile already sources .bashrc but is somehow not exporting the variables? (otherwise I wouldn't have this problem)
https://redd.it/1ovfib3
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
i am working on a posix virtual machine with reader macros so i can rewrite the rules of the shell live while its running, to interpret or wite a compiler for any language. moving beyond the syntax of posix by force. i have been told to ask questions rather than assert. i decline.
awkmacrovm(){ awk 'BEGIN{r0=0;r1=1;rx=1;ic=1;while(rx){x=substr(ci,ic,1);y=substr(ci,ic+1,1);z=substr(ci,ic+2,1);if(z == "-"){rx-=ry}; else if(z == "<"){rx=rx<ry}; else if(z == "m"){ry=rx}; else if(z == "$"){rx=system(ry)}; else if(z == "r"){rx=rr[y]}; else if(z == "w"){rr[y] = rx}; else if(z == "i"){getline rx}; else if(z == "o"){printf "%s", rx}; else if(z == "+"){rx=rx ry}; else if(z == "c"){rx = sprintf("%c", ry)}; else if(z == "#"){rx = ord(ry)}; else if(z == "s"){rx=substr(rx,ry,1)};else if(z == "x"){ic=-2;ci=rx}; ic+=3};};' ci="$1";};
https://redd.it/1ovj54b
@r_bash
awkmacrovm(){ awk 'BEGIN{r0=0;r1=1;rx=1;ic=1;while(rx){x=substr(ci,ic,1);y=substr(ci,ic+1,1);z=substr(ci,ic+2,1);if(z == "-"){rx-=ry}; else if(z == "<"){rx=rx<ry}; else if(z == "m"){ry=rx}; else if(z == "$"){rx=system(ry)}; else if(z == "r"){rx=rr[y]}; else if(z == "w"){rr[y] = rx}; else if(z == "i"){getline rx}; else if(z == "o"){printf "%s", rx}; else if(z == "+"){rx=rx ry}; else if(z == "c"){rx = sprintf("%c", ry)}; else if(z == "#"){rx = ord(ry)}; else if(z == "s"){rx=substr(rx,ry,1)};else if(z == "x"){ic=-2;ci=rx}; ic+=3};};' ci="$1";};
https://redd.it/1ovj54b
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
potd (Pokémon of the Day) - a new random Pokémon for your terminal every day!
[silly little pokemon in the silly little terminal being silly little guys](https://preview.redd.it/ni9gt36fow0g1.png?width=1081&format=png&auto=webp&s=3a4e400a75f29f178f260b58dcc510844e277e4e)
Hi all :)
Just something silly I've been working on since last night. I'm sure it's been done a million times in a million better ways, so if you are aware of any others I'd love to see them!
The noscript uses [pokeget-rs](https://github.com/talwat/pokeget-rs) to retrieve the sprites, so make sure it's available in your $PATH before running this.
Every time the noscript is launched it seeds the $RANDOM value in bash with the current date as a unix timestamp (snapped to 00:00). This value is used to generate the Pokédex ID, ensuring the same Pokémon appears consistently for the entire day.
After that, $RANDOM is seeded again using the current date as a unix timestamp (this time snapped to the last 5 minutes). This value is used to check if the Pokémon should be shiny (1/128 chance), meaning that a Pokémon can be shiny for 5 minutes before the next roll happens.
I also added `--fetch` as an argument which will display a few lines of info next to the sprite:
1. `kn` is the current kernel version
2. `sh` is the current shell
3. `up` is the current uptime
4. `potd` lists the Pokémon's name followed by it's Pokédex ID in parenthesis
5. `seen` shows when you first saw this Pokémon
6. `shny` shows when you first saw the shiny variant of this Pokémon
If you have any tips on how I could improve this, please let me know! It's just a fun little thing I'm working on but I'd love to make it more efficient.
Full noscript:
#!/usr/bin/env bash
for i in "$@"; do
case $i in
"-v" | "--verbose")
# output the pokemon info to stderr
OPT_VERBOSE=1
;;
"-f" | "--fetch")
# include system info alongside the sprite
OPT_FETCH=1
;;
esac
done
CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config} # should almost always return `$HOME/.config`
POTD_DIR="${CONFIG_DIR}/potd" # the config directory that this noscript will use to store everything
POTD_CACHE="${POTD_DIR}/cache" # used to record which sprites have appeared before
POKEGET_CMD='pokeget' # requires pokeget-rs for the pretty small sprites
POKEGET_ARGS=('') # add any extra args for pokeget-rs here
MAX_DEX_ID=905 # max pokedex id in pokeget-rs. decrease this number to limit to specific generations.
# ansi escape codes for colours + style
HEAD='\e[34m'
DATA='\033[38;2;200;166;247m'
DATA='\e[35m'
SHINY='\e[33m'
BOLD='\e[1m'
RESET='\e[0m'
# seed the bash random number with the current date, snapped to midnight, as a unix timestamp
pokemon_seed=$(date --date "00:00" +%s)
RANDOM=${pokemon_seed}
pokedex_id=$((RANDOM % MAX_DEX_ID))
POKEGET_ARGS=("$pokedex_id" "${POKEGET_ARGS[@]}")
sprite_path="${POTD_CACHE}/${pokedex_id}"
# roll for a shiny
shiny_seed=$(date +%s)
shiny_seed=$((shiny_seed - (shiny_seed % 300)))
RANDOM=${shiny_seed}
shiny_roll=$((RANDOM % 128))
if [ $shiny_roll -eq 0 ]; then
POKEGET_ARGS+=('--shiny')
sprite_path="${sprite_path}-shiny"
fi
# check if this sprite has been saved yet
[ -d ${POTD_DIR} ] || mkdir ${POTD_DIR}
[ -d ${POTD_CACHE} ] || mkdir ${POTD_CACHE}
if ! [ -f ${sprite_path} ]; then
echo "$pokemon_seed" >$sprite_path # first seen value
$POKEGET_CMD ${POKEGET_ARGS[@]} >>$sprite_path 2>&1
fi
pokemon_name="$(sed '2q;d' $sprite_path)"
first_seen="$(head -n 1 $sprite_path)"
# extract the shiny encounter date if available
if [ $shiny_roll -eq 0 ]; then
shiny_seen=$(head -n 1 "${sprite_path}")
else
[ -f "${sprite_path}-shiny" ] && shiny_seen=$(head -n 1 "${sprite_path}-shiny") || shiny_seen=0
fi
# get
[silly little pokemon in the silly little terminal being silly little guys](https://preview.redd.it/ni9gt36fow0g1.png?width=1081&format=png&auto=webp&s=3a4e400a75f29f178f260b58dcc510844e277e4e)
Hi all :)
Just something silly I've been working on since last night. I'm sure it's been done a million times in a million better ways, so if you are aware of any others I'd love to see them!
The noscript uses [pokeget-rs](https://github.com/talwat/pokeget-rs) to retrieve the sprites, so make sure it's available in your $PATH before running this.
Every time the noscript is launched it seeds the $RANDOM value in bash with the current date as a unix timestamp (snapped to 00:00). This value is used to generate the Pokédex ID, ensuring the same Pokémon appears consistently for the entire day.
After that, $RANDOM is seeded again using the current date as a unix timestamp (this time snapped to the last 5 minutes). This value is used to check if the Pokémon should be shiny (1/128 chance), meaning that a Pokémon can be shiny for 5 minutes before the next roll happens.
I also added `--fetch` as an argument which will display a few lines of info next to the sprite:
1. `kn` is the current kernel version
2. `sh` is the current shell
3. `up` is the current uptime
4. `potd` lists the Pokémon's name followed by it's Pokédex ID in parenthesis
5. `seen` shows when you first saw this Pokémon
6. `shny` shows when you first saw the shiny variant of this Pokémon
If you have any tips on how I could improve this, please let me know! It's just a fun little thing I'm working on but I'd love to make it more efficient.
Full noscript:
#!/usr/bin/env bash
for i in "$@"; do
case $i in
"-v" | "--verbose")
# output the pokemon info to stderr
OPT_VERBOSE=1
;;
"-f" | "--fetch")
# include system info alongside the sprite
OPT_FETCH=1
;;
esac
done
CONFIG_DIR=${XDG_CONFIG_HOME:-$HOME/.config} # should almost always return `$HOME/.config`
POTD_DIR="${CONFIG_DIR}/potd" # the config directory that this noscript will use to store everything
POTD_CACHE="${POTD_DIR}/cache" # used to record which sprites have appeared before
POKEGET_CMD='pokeget' # requires pokeget-rs for the pretty small sprites
POKEGET_ARGS=('') # add any extra args for pokeget-rs here
MAX_DEX_ID=905 # max pokedex id in pokeget-rs. decrease this number to limit to specific generations.
# ansi escape codes for colours + style
HEAD='\e[34m'
DATA='\033[38;2;200;166;247m'
DATA='\e[35m'
SHINY='\e[33m'
BOLD='\e[1m'
RESET='\e[0m'
# seed the bash random number with the current date, snapped to midnight, as a unix timestamp
pokemon_seed=$(date --date "00:00" +%s)
RANDOM=${pokemon_seed}
pokedex_id=$((RANDOM % MAX_DEX_ID))
POKEGET_ARGS=("$pokedex_id" "${POKEGET_ARGS[@]}")
sprite_path="${POTD_CACHE}/${pokedex_id}"
# roll for a shiny
shiny_seed=$(date +%s)
shiny_seed=$((shiny_seed - (shiny_seed % 300)))
RANDOM=${shiny_seed}
shiny_roll=$((RANDOM % 128))
if [ $shiny_roll -eq 0 ]; then
POKEGET_ARGS+=('--shiny')
sprite_path="${sprite_path}-shiny"
fi
# check if this sprite has been saved yet
[ -d ${POTD_DIR} ] || mkdir ${POTD_DIR}
[ -d ${POTD_CACHE} ] || mkdir ${POTD_CACHE}
if ! [ -f ${sprite_path} ]; then
echo "$pokemon_seed" >$sprite_path # first seen value
$POKEGET_CMD ${POKEGET_ARGS[@]} >>$sprite_path 2>&1
fi
pokemon_name="$(sed '2q;d' $sprite_path)"
first_seen="$(head -n 1 $sprite_path)"
# extract the shiny encounter date if available
if [ $shiny_roll -eq 0 ]; then
shiny_seen=$(head -n 1 "${sprite_path}")
else
[ -f "${sprite_path}-shiny" ] && shiny_seen=$(head -n 1 "${sprite_path}-shiny") || shiny_seen=0
fi
# get
system info (shamelessly lifted from cutefetch)
get_uptime() {
local up=$(uptime)
up=${up#*up } # remove everything before "up "
up=${up%%,*} # remove everything after first comma
echo $up | xargs # trim whitespace
}
systeminfo=()
if ! [ -z ${OPT_FETCH+x} ]; then
systeminfo[0]="${BOLD}${HEAD}kn${RESET} ${DATA}$(uname -r | cut -f1 -d '-')"
systeminfo[1]="${BOLD}${HEAD}sh${RESET} ${DATA}$(basename $SHELL)"
systeminfo[2]="${BOLD}${HEAD}up${RESET} ${DATA}$(get_uptime)"
# store the pokemon info along with the system info
[ $shiny_roll -eq 0 ] && systeminfo[4]="${BOLD}${HEAD}potd${RESET} ${BOLD}${SHINY}${pokemon_name,,} (${pokedex_id})" || systeminfo[4]="${BOLD}${HEAD}potd${RESET} ${DATA}${pokemon_name,,} (${pokedex_id})"
[ $first_seen -eq $pokemon_seed ] && systeminfo[5]="${BOLD}${HEAD}seen${RESET} ${DATA}today" || systeminfo[5]="${BOLD}${HEAD}seen${RESET} ${DATA}$((first_seen % 60 % 60 % 24)) days ago"
case $shiny_seen in
0)
systeminfo[6]="${BOLD}${HEAD}shny${RESET} ${DATA}never seen"
;;
$pokemon_seed)
systeminfo[6]="${BOLD}${HEAD}shny${RESET} ${DATA}today"
;;
*)
systeminfo[6]="${BOLD}${HEAD}shny${RESET} ${DATA}$((shiny_seen % 60 % 60 % 24)) days ago"
;;
esac
fi
# print the pokemon info to stderr if -v or --verbose was passed
[ -z ${OPT_VERBOSE+x} ] || >&2 echo -e "dex_id: ${pokedex_id}\npkmn_name: ${pokemon_name}\nshiny_roll: ${shiny_roll}\npkmn_seed: ${pokemon_seed}\nshiny_seed: ${shiny_seed}\nfirst_seen: ${first_seen}"
# iterate over every line in the sprite, appending system info when available
index=0
tail -n +3 ${sprite_path} | while IFS= read -r line; do
[ $index -le ${#systeminfo[@]} ] && echo -e "${line} ${systeminfo[$index]}" || echo "${line}"
index=$((index + 1))
done
https://redd.it/1ovk9rn
@r_bash
get_uptime() {
local up=$(uptime)
up=${up#*up } # remove everything before "up "
up=${up%%,*} # remove everything after first comma
echo $up | xargs # trim whitespace
}
systeminfo=()
if ! [ -z ${OPT_FETCH+x} ]; then
systeminfo[0]="${BOLD}${HEAD}kn${RESET} ${DATA}$(uname -r | cut -f1 -d '-')"
systeminfo[1]="${BOLD}${HEAD}sh${RESET} ${DATA}$(basename $SHELL)"
systeminfo[2]="${BOLD}${HEAD}up${RESET} ${DATA}$(get_uptime)"
# store the pokemon info along with the system info
[ $shiny_roll -eq 0 ] && systeminfo[4]="${BOLD}${HEAD}potd${RESET} ${BOLD}${SHINY}${pokemon_name,,} (${pokedex_id})" || systeminfo[4]="${BOLD}${HEAD}potd${RESET} ${DATA}${pokemon_name,,} (${pokedex_id})"
[ $first_seen -eq $pokemon_seed ] && systeminfo[5]="${BOLD}${HEAD}seen${RESET} ${DATA}today" || systeminfo[5]="${BOLD}${HEAD}seen${RESET} ${DATA}$((first_seen % 60 % 60 % 24)) days ago"
case $shiny_seen in
0)
systeminfo[6]="${BOLD}${HEAD}shny${RESET} ${DATA}never seen"
;;
$pokemon_seed)
systeminfo[6]="${BOLD}${HEAD}shny${RESET} ${DATA}today"
;;
*)
systeminfo[6]="${BOLD}${HEAD}shny${RESET} ${DATA}$((shiny_seen % 60 % 60 % 24)) days ago"
;;
esac
fi
# print the pokemon info to stderr if -v or --verbose was passed
[ -z ${OPT_VERBOSE+x} ] || >&2 echo -e "dex_id: ${pokedex_id}\npkmn_name: ${pokemon_name}\nshiny_roll: ${shiny_roll}\npkmn_seed: ${pokemon_seed}\nshiny_seed: ${shiny_seed}\nfirst_seen: ${first_seen}"
# iterate over every line in the sprite, appending system info when available
index=0
tail -n +3 ${sprite_path} | while IFS= read -r line; do
[ $index -le ${#systeminfo[@]} ] && echo -e "${line} ${systeminfo[$index]}" || echo "${line}"
index=$((index + 1))
done
https://redd.it/1ovk9rn
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
OC An image compression bash
This is an image compression bash I made to do the following tasks (jpg, jpeg only):
1. Limit the maximum height/width to 2560 pixels by proportional scaling.
2. Limit the file size to scaled (height * width * 0.15) bytes.
\---
https://redd.it/1ow3302
@r_bash
This is an image compression bash I made to do the following tasks (jpg, jpeg only):
1. Limit the maximum height/width to 2560 pixels by proportional scaling.
2. Limit the file size to scaled (height * width * 0.15) bytes.
\---
#!/bin/bashmax_dim=2560for input in *.jpg; do# Skip if no jpg files found[ -e "$input" ] || continueoutput="${input%.*}_compressed.jpg"# Get original dimensionswidth=$(identify -format "%w" "$input")height=$(identify -format "%h" "$input")# Check if resizing is neededif [ $width -le $max_dim ] && [ $height -le $max_dim ]; then# No resize needed, just copy input to outputcp "$input" "$output"target_width=$widthtarget_height=$heightelse# Determine scale factor to limit max dimension to 2560 pixelsif [ $width -gt $height ]; thenscale=$(echo "scale=4; $max_dim / $width" | bc)elsescale=$(echo "scale=4; $max_dim / $height" | bc)fi# Calculate new dimensions after scalingtarget_width=$(printf "%.0f" $(echo "$width * $scale" | bc))target_height=$(printf "%.0f" $(echo "$height * $scale" | bc))# Resize image proportionally with ImageMagick convertconvert "$input" -resize "${target_width}x${target_height}" "$output"fi# Calculate target file size limit in bytes (width * height * 0.15)target_size=$(printf "%.0f" $(echo "$target_width * $target_height * 0.15" | bc))actual_size=$(stat -c%s "$output")# Run jpegoptim only if target_size is less than actual file sizeif [ $target_size -lt $actual_size ]; thenjpegoptim --size=${target_size} --strip-all "$output"actual_size=$(stat -c%s "$output")fiecho "Processed $input -> $output"echo "Final dimensions: ${target_width}x${target_height}"echo "Final file size: $actual_size bytes (target was $target_size bytes)"donehttps://redd.it/1ow3302
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
Decompression & Interpretation Of JPEG
As the noscript suggests could you potentially do a decompression of advanced file systems such as JPEG or PNG, but the limitation of using bash builtins (Use ‘type -t {command}’ to check if a command is built in) only, & preferably running ok.
https://redd.it/1owxgcu
@r_bash
As the noscript suggests could you potentially do a decompression of advanced file systems such as JPEG or PNG, but the limitation of using bash builtins (Use ‘type -t {command}’ to check if a command is built in) only, & preferably running ok.
https://redd.it/1owxgcu
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
Simple tool that automates tasks by creating rootless containers displayed in tmux
https://redd.it/1oxc1gu
@r_bash
https://redd.it/1oxc1gu
@r_bash
Reddit
From the bash community on Reddit: Simple tool that automates tasks by creating rootless containers displayed in tmux
Explore this post and more from the bash community
TUI File Manager in Bash
https://preview.redd.it/ao14kf51nh1g1.png?width=1914&format=png&auto=webp&s=647a8623a329e0ac3f61e241b04c40f2736b43f2
Checkout this file manager i made in pure bash
Do give a star if you like it - https://github.com/Aarnya-Jain/bashfm
https://redd.it/1oy3chh
@r_bash
https://preview.redd.it/ao14kf51nh1g1.png?width=1914&format=png&auto=webp&s=647a8623a329e0ac3f61e241b04c40f2736b43f2
Checkout this file manager i made in pure bash
Do give a star if you like it - https://github.com/Aarnya-Jain/bashfm
https://redd.it/1oy3chh
@r_bash
Accidentally created an emotional OS
\#!/usr/bin/env bash
\# feralChurchBasementOS.sh
\# emotional maintenance noscript for unstable human systems
set -euo pipefail
OS_NAME="feralChurchBasementOS"
VERSION="v1.0"
log() {
printf "[%s\] %s\\n" "$(date +'%Y-%m-%d %H:%M:%S')" "$*"
}
uninstall_shame() {
log "Purging inherited shame..."
\# placeholder for actual work
sleep 1
log "Shame removed from user-space (may respawn, monitor with journalctl)."
}
reboot_self_worth() {
log "Rebooting self-worth service..."
\# simulate stop/start
sleep 1
log "self-worth.service is now active (running)."
}
patch_trauma_kernel() {
log "Applying trauma kernel patches..."
\# pretend to apply updates
sleep 1
log "Kernel patched. Reboot recommended for changes to take full effect."
}
close_background_processes() {
log "Scanning for emotional background processes..."
\# pretend to kill runaway processes
sleep 1
log "Terminated: overthinking, catastrophizing, people-pleasing."
}
restrict_root_access() {
log "Hardening permissions on /home/heart..."
\# pretend to change ownership/permissions
sleep 1
log "Root access to feelings restricted. Sudo now requires consent."
}
run_health_check() {
log "Running post-maintenance health check..."
sleep 1
log "System status: degraded but functional (expected)."
}
main() {
log "Initializing ${OS_NAME} ${VERSION}..."
uninstall_shame
reboot_self_worth
patch_trauma_kernel
close_background_processes
restrict_root_access
run_health_check
log "Done. For ongoing maintenance, schedule via cron:"
log " 0 3 * * * ${PWD}/feralChurchBasementOS.sh >/var/log/basementOS.log 2>&1"
log "Manual override available with: sudo apt-get heal"
}
main "$@"
https://redd.it/1oyqzgo
@r_bash
\#!/usr/bin/env bash
\# feralChurchBasementOS.sh
\# emotional maintenance noscript for unstable human systems
set -euo pipefail
OS_NAME="feralChurchBasementOS"
VERSION="v1.0"
log() {
printf "[%s\] %s\\n" "$(date +'%Y-%m-%d %H:%M:%S')" "$*"
}
uninstall_shame() {
log "Purging inherited shame..."
\# placeholder for actual work
sleep 1
log "Shame removed from user-space (may respawn, monitor with journalctl)."
}
reboot_self_worth() {
log "Rebooting self-worth service..."
\# simulate stop/start
sleep 1
log "self-worth.service is now active (running)."
}
patch_trauma_kernel() {
log "Applying trauma kernel patches..."
\# pretend to apply updates
sleep 1
log "Kernel patched. Reboot recommended for changes to take full effect."
}
close_background_processes() {
log "Scanning for emotional background processes..."
\# pretend to kill runaway processes
sleep 1
log "Terminated: overthinking, catastrophizing, people-pleasing."
}
restrict_root_access() {
log "Hardening permissions on /home/heart..."
\# pretend to change ownership/permissions
sleep 1
log "Root access to feelings restricted. Sudo now requires consent."
}
run_health_check() {
log "Running post-maintenance health check..."
sleep 1
log "System status: degraded but functional (expected)."
}
main() {
log "Initializing ${OS_NAME} ${VERSION}..."
uninstall_shame
reboot_self_worth
patch_trauma_kernel
close_background_processes
restrict_root_access
run_health_check
log "Done. For ongoing maintenance, schedule via cron:"
log " 0 3 * * * ${PWD}/feralChurchBasementOS.sh >/var/log/basementOS.log 2>&1"
log "Manual override available with: sudo apt-get heal"
}
main "$@"
https://redd.it/1oyqzgo
@r_bash
Script to re-assemble HTML email chopped up by fetchmail/procmail
I use "fetchmail" to pull down email via POP3, with "procmail" handling delivery, and "mutt" as my mailreader. Long lines in emails are split and wrapped. Sometimes I get a web page as an email for authentication. Usually the first 74 characters of each long line are as-is, followed by "=" followed by newline followed by the rest of the line. If the line is really long, it'll get chopped into multiple lines. Sometimes, it's 75-character-chunks of the line followed by "=".
I can re-assemble the original webpage-email manually with vim, but it's a long, painfull, error-prone process. I came up with the following noscript to do it for me. I call the noscript "em2html". It requires exactly 2 input parameters...
- the original raw email file name
- the desired output file name, to open with a web browser. The name should have a ".htm" or ".html" extension so that a web browser can open it.
Once you have the output file, open it locally with a web browser. I had originally intended to "echo" directly to the final output file, and edit in place with "ed", but "ed" is not included in my distro, and possibly yours. Therefore I use "mktemp" to create an interim scratch file. I have not yet developed an algorithm to remove email headers, without risking removing too much. Here's the noscript...
~~~
#!/bin/bash
if ${#} -ne 2 ; then
echo 'ERROR The noscript requires exactly 2 parameters, namely'
echo 'the input file name and the output file name. It is recommended'
echo 'that the output file name have a ".htm" or ".html" extension'
echo 'so that it is treated as an HTML file.'
exit
fi
tempfile="$(mktemp)"
while read
do
if "${REPLY: -1}" = "=" ; then
xlength=$(( ${#REPLY} - 1 ))
echo -n "${REPLY:0:${xlength}}" >> "${tempfile}"
else
echo "${REPLY}" >> "${tempfile}"
fi
done<"${1}"
sed "s/=09/\t/g
s/=3D/=/g" "${tempfile}" > "${2}"
rm -rf "${tempfile}"
~~~
https://redd.it/1ozghjm
@r_bash
I use "fetchmail" to pull down email via POP3, with "procmail" handling delivery, and "mutt" as my mailreader. Long lines in emails are split and wrapped. Sometimes I get a web page as an email for authentication. Usually the first 74 characters of each long line are as-is, followed by "=" followed by newline followed by the rest of the line. If the line is really long, it'll get chopped into multiple lines. Sometimes, it's 75-character-chunks of the line followed by "=".
I can re-assemble the original webpage-email manually with vim, but it's a long, painfull, error-prone process. I came up with the following noscript to do it for me. I call the noscript "em2html". It requires exactly 2 input parameters...
- the original raw email file name
- the desired output file name, to open with a web browser. The name should have a ".htm" or ".html" extension so that a web browser can open it.
Once you have the output file, open it locally with a web browser. I had originally intended to "echo" directly to the final output file, and edit in place with "ed", but "ed" is not included in my distro, and possibly yours. Therefore I use "mktemp" to create an interim scratch file. I have not yet developed an algorithm to remove email headers, without risking removing too much. Here's the noscript...
~~~
#!/bin/bash
if ${#} -ne 2 ; then
echo 'ERROR The noscript requires exactly 2 parameters, namely'
echo 'the input file name and the output file name. It is recommended'
echo 'that the output file name have a ".htm" or ".html" extension'
echo 'so that it is treated as an HTML file.'
exit
fi
tempfile="$(mktemp)"
while read
do
if "${REPLY: -1}" = "=" ; then
xlength=$(( ${#REPLY} - 1 ))
echo -n "${REPLY:0:${xlength}}" >> "${tempfile}"
else
echo "${REPLY}" >> "${tempfile}"
fi
done<"${1}"
sed "s/=09/\t/g
s/=3D/=/g" "${tempfile}" > "${2}"
rm -rf "${tempfile}"
~~~
https://redd.it/1ozghjm
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
New Project: “GeoBlocker” — US-only SSH Geo-fencing with nftables (feedback welcome!)
https://redd.it/1p05fuu
@r_bash
https://redd.it/1p05fuu
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
imgur album fetcher
I'll just leave this here:
for x in $(curl https://imgur.com/gallery/ultimate-4k-wallpaper-dump-2-cats-8Yxub | awk -F 'window.postDataJSON="' '{print $2}' | awk -F '"</noscript>' '{print $1}' | sed 's/\\//g' | jq '.media.[].url' | sed 's/"//g'); do timeout 5 curl "$x" > "${x##*/}"; done
https://redd.it/1p0nbii
@r_bash
I'll just leave this here:
for x in $(curl https://imgur.com/gallery/ultimate-4k-wallpaper-dump-2-cats-8Yxub | awk -F 'window.postDataJSON="' '{print $2}' | awk -F '"</noscript>' '{print $1}' | sed 's/\\//g' | jq '.media.[].url' | sed 's/"//g'); do timeout 5 curl "$x" > "${x##*/}"; done
https://redd.it/1p0nbii
@r_bash
New Project: “GeoBlocker” — US-only SSH Geo-fencing with nftables (feedback welcome!)
Hey everyone,
I’m pretty new to sharing code publicly, so please be gentle 😅 — but I’ve been working on something I think could be useful to others, and I’d love feedback from people far more experienced than me.
# 🔒 What is GeoBlocker?
GeoBlocker is a Bash-based tool for Ubuntu 24.04 servers that want to lock down SSH (port 22) to US IP ranges only, using fast-loading nftables sets and geo-IP lists from IPdeny.
Features:
Fetches US IPv4 + IPv6 ranges (with IPdeny usage-limits respected)
Bulk-loads them efficiently into nftables sets (avoiding slow “one CIDR at a time” loops)
Optional SSH whitelist (IPv4 + IPv6)
Investigation mode that shows:
nftables status
whitelist status
SSH client IP
privileges
missing sets or config issues
Backup + atomic write safety
Nothing applied automatically — you stay in control of `/etc/nftables.conf`
Repo is here:
👉 [https://github.com/baerrs/GeoBlocker](https://github.com/baerrs/GeoBlocker)
# 🛠️ Why I built it
I run a small personal server and kept seeing tons of SSH brute-force attempts from around the world.
Fail2ban helped, but I wanted a stronger approach: just block every non-US address before they even reach SSH.
I found a lot of half-solutions or outdated guides, so I wrote a noscript that:
is reproducible
uses best practices
keeps nftables clean
and is safe for beginners (backups, dry-run behavior, etc.)
# 🙋♂️ What I want feedback on
Since I’m new to publishing open-source noscripts:
Is the structure reasonable?
Any obvious improvements to safety, portability, or code style?
Is the README clear enough?
Any red flags for production usage?
Suggestions for features? (cron auto-update? IPv4/v6 country selection? Better logging?)
I’m totally open to constructive criticism — just keep in mind I’m still learning how to present and share code. ❤️
# Thanks in advance!
If anyone has ideas, corrections, or wants to help evolve the project, I’d really appreciate it.
And if even one person finds it useful, that’s a big win for me already.
Thanks! 🙏
— Scott (R. Scott Baer)
https://redd.it/1p11m9l
@r_bash
Hey everyone,
I’m pretty new to sharing code publicly, so please be gentle 😅 — but I’ve been working on something I think could be useful to others, and I’d love feedback from people far more experienced than me.
# 🔒 What is GeoBlocker?
GeoBlocker is a Bash-based tool for Ubuntu 24.04 servers that want to lock down SSH (port 22) to US IP ranges only, using fast-loading nftables sets and geo-IP lists from IPdeny.
Features:
Fetches US IPv4 + IPv6 ranges (with IPdeny usage-limits respected)
Bulk-loads them efficiently into nftables sets (avoiding slow “one CIDR at a time” loops)
Optional SSH whitelist (IPv4 + IPv6)
Investigation mode that shows:
nftables status
whitelist status
SSH client IP
privileges
missing sets or config issues
Backup + atomic write safety
Nothing applied automatically — you stay in control of `/etc/nftables.conf`
Repo is here:
👉 [https://github.com/baerrs/GeoBlocker](https://github.com/baerrs/GeoBlocker)
# 🛠️ Why I built it
I run a small personal server and kept seeing tons of SSH brute-force attempts from around the world.
Fail2ban helped, but I wanted a stronger approach: just block every non-US address before they even reach SSH.
I found a lot of half-solutions or outdated guides, so I wrote a noscript that:
is reproducible
uses best practices
keeps nftables clean
and is safe for beginners (backups, dry-run behavior, etc.)
# 🙋♂️ What I want feedback on
Since I’m new to publishing open-source noscripts:
Is the structure reasonable?
Any obvious improvements to safety, portability, or code style?
Is the README clear enough?
Any red flags for production usage?
Suggestions for features? (cron auto-update? IPv4/v6 country selection? Better logging?)
I’m totally open to constructive criticism — just keep in mind I’m still learning how to present and share code. ❤️
# Thanks in advance!
If anyone has ideas, corrections, or wants to help evolve the project, I’d really appreciate it.
And if even one person finds it useful, that’s a big win for me already.
Thanks! 🙏
— Scott (R. Scott Baer)
https://redd.it/1p11m9l
@r_bash
GitHub
GitHub - baerrs/GeoBlocker: Geo Blocking
Geo Blocking . Contribute to baerrs/GeoBlocker development by creating an account on GitHub.
Built my own xdg-open alternative because the old one annoyed me — meet YAXO
https://github.com/yogeshdofficial/yaxo
https://redd.it/1p1f8ji
@r_bash
https://github.com/yogeshdofficial/yaxo
https://redd.it/1p1f8ji
@r_bash
GitHub
GitHub - yogeshdofficial/yaxo: Modern replacement for xdg-open
Modern replacement for xdg-open. Contribute to yogeshdofficial/yaxo development by creating an account on GitHub.
i am loosing my mind, help me with bash plz.....
ai: (gpt)
is that a thing really in bash noscripting. bro. i lost hours trying fixing this with gemini cli. finally got this from gpt.
i wrote that line to stop to read "found"
cause my program had tui staff so if i hadn't done that the output would vanish.
bro i am noscripting i have no time for that. after that many days coding with bash... finally this????
idk why but after commenting out the read line it works. how can i avoid unintentional situations like that. this interrupts my flow of work.
https://redd.it/1p1vzik
@r_bash
[[ -f "$dotfiles_path/installer.sh" ]] && echo found
read -n 1 -s -r
if [ -f "$dotfiles_path/installer.sh" ]; then
ai: (gpt)
❗ read -n 1 -s -r breaks the [[ ... ]] test output
read -n 1 reads nothing (because Enter is a newline, not a character key),
leaving the newline in the buffer.
So the NEXT read or the control flow may get triggered early.
This results in:
skipped prompts
next input read incorrectly
if branches executing before expected
depending on where the leftover newline is consumed.
is that a thing really in bash noscripting. bro. i lost hours trying fixing this with gemini cli. finally got this from gpt.
i wrote that line to stop to read "found"
cause my program had tui staff so if i hadn't done that the output would vanish.
bro i am noscripting i have no time for that. after that many days coding with bash... finally this????
idk why but after commenting out the read line it works. how can i avoid unintentional situations like that. this interrupts my flow of work.
https://redd.it/1p1vzik
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
HELP ME
#!/bin/bash
# Decrypt function
function decrypt {
MzSaas7k=$(echo $hash | sed 's/988sn1/83unasa/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/4d298d/9999/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/3i8dqos82/873h4d/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/4n9Ls/20X/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/912oijs01/i7gg/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/k32jx0aa/n391s/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/nI72n/YzF1/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/82ns71n/2d49/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/JGcms1a/zIm12/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/MS9/4SIs/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/Ymxj00Ims/Uso18/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/sSi8Lm/Mit/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/9su2n/43n92ka/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/ggf3iunds/dn3i8/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/uBz/TT0K/g')
flag=$(echo $MzSaas7k | base64 -d | openssl enc -aes-128-cbc -a -d -salt -pass pass:$salt)
}
# Variables
var="9M"
salt=""
hash="VTJGc2RHVmtYMTl2ZnYyNTdUeERVRnBtQWVGNmFWWVUySG1wTXNmRi9rQT0K"
# Base64 Encoding Example:
# $ echo "Some Text" | base64
# <- For-Loop here
# Check if $salt is empty
if [ ! -z "$salt" ]
then
decrypt
echo $flag
else
exit 1
fi
Create a "For" loop that encodes the variable "var" 28 times in "base64". The number of characters in the 28th hash is the value that must be assigned to the "salt" variable.
I have tried every single line of code that i know and still didn't get the right answer
https://redd.it/1p1zx87
@r_bash
#!/bin/bash
# Decrypt function
function decrypt {
MzSaas7k=$(echo $hash | sed 's/988sn1/83unasa/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/4d298d/9999/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/3i8dqos82/873h4d/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/4n9Ls/20X/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/912oijs01/i7gg/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/k32jx0aa/n391s/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/nI72n/YzF1/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/82ns71n/2d49/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/JGcms1a/zIm12/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/MS9/4SIs/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/Ymxj00Ims/Uso18/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/sSi8Lm/Mit/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/9su2n/43n92ka/g')
Mzns7293sk=$(echo $MzSaas7k | sed 's/ggf3iunds/dn3i8/g')
MzSaas7k=$(echo $Mzns7293sk | sed 's/uBz/TT0K/g')
flag=$(echo $MzSaas7k | base64 -d | openssl enc -aes-128-cbc -a -d -salt -pass pass:$salt)
}
# Variables
var="9M"
salt=""
hash="VTJGc2RHVmtYMTl2ZnYyNTdUeERVRnBtQWVGNmFWWVUySG1wTXNmRi9rQT0K"
# Base64 Encoding Example:
# $ echo "Some Text" | base64
# <- For-Loop here
# Check if $salt is empty
if [ ! -z "$salt" ]
then
decrypt
echo $flag
else
exit 1
fi
Create a "For" loop that encodes the variable "var" 28 times in "base64". The number of characters in the 28th hash is the value that must be assigned to the "salt" variable.
I have tried every single line of code that i know and still didn't get the right answer
https://redd.it/1p1zx87
@r_bash
Reddit
From the bash community on Reddit
Explore this post and more from the bash community
Concurrency and Strict Mode
I added a chapter about Bash and Concurrency in my small Bash Strict Mode Guide:
https://github.com/guettli/bash-strict-mode?tab=readme-ov-file#general-bash-hints-concurrency
Feedback is welcome:
## General Bash Hints: Concurrency
If you want to execute two tasks concurrently, you can do it like this:
Why wait each PID separately?
- You must wait to reap background children and avoid zombies.
-
waited for. This means an earlier background job can fail yet the combined
success if the last job succeeds — not what you want if you need to detect failures reliably.
https://redd.it/1p20iz7
@r_bash
I added a chapter about Bash and Concurrency in my small Bash Strict Mode Guide:
https://github.com/guettli/bash-strict-mode?tab=readme-ov-file#general-bash-hints-concurrency
Feedback is welcome:
## General Bash Hints: Concurrency
If you want to execute two tasks concurrently, you can do it like this:
# Bash Strict Mode: https://github.com/guettli/bash-strict-mode
trap 'echo -e "\n🤷 🚨 🔥 Warning: A command has failed. Exiting the noscript. Line was ($0:$LINENO): $(sed -n "${LINENO}p" "$0" 2>/dev/null || true) 🔥 🚨 🤷 "; exit 3' ERR
set -Eeuo pipefail
{
echo task 1
sleep 1
} & task1_pid=$!
{
echo task 2
sleep 2
} & task2_pid=$!
# Wait each PID on its own line so you get each child's exit status.
wait "$task1_pid"
wait "$task2_pid"
echo end
Why wait each PID separately?
- You must wait to reap background children and avoid zombies.
-
wait pid1 pid2 will wait for both PIDs, but its exit status is the exit status of the last PIDwaited for. This means an earlier background job can fail yet the combined
wait can still returnsuccess if the last job succeeds — not what you want if you need to detect failures reliably.
https://redd.it/1p20iz7
@r_bash
GitHub
GitHub - guettli/bash-strict-mode: Bash Strict Mode
Bash Strict Mode. Contribute to guettli/bash-strict-mode development by creating an account on GitHub.