r_bash – Telegram
Get filename expansion to work with “here strings”?

Unless -f is specified, bash expands filenames as stated here:

% echo /var/cache/*
/var/cache/apk /var/cache/misc


But I was pretty surprised that this one didn’t work as expected:

cat <<< /var/cache/*
/var/cache/*


In this page about here strings it’s clearly written:

> Filename expansion and word splitting are not performed.

There is no information on how to get filename expansions to work with this syntax. Shell flags? Patches? Workarounds? Any particular reason why it does variable expansion in here strings, but not filename one?

Thanks!





https://redd.it/1ph92p9
@r_bash
I made this Bash keyboard shortcuts map because I was tired of forgetting them 😅

Hey everyone!



I’ve always seen visual “keyboard maps” for apps like GIMP, Photoshop, Blender,

etc. — where each key is labeled with its shortcut. But I realized I had never

seen a version of that style specifically for Bash / Readline shortcuts.



So I decided to design one.



Part of the inspiration came from the classic Vi/Vim cheat sheet from ViEmu:

http://www.viemu.com/a\_vi\_vim\_graphical\_cheat\_sheet\_tutorial.html

What I really liked was how it uses the keyboard itself as the visual foundation,

and how the shortcuts are introduced progressively rather than all at once.

I wanted to recreate that idea for Bash/Readline, since most Bash shortcut

references are just plain text lists.



Following that concept, I made **four versions** of the Bash shortcuts map,

ranging from a very basic level to more advanced ones, so learners can progress

naturally as they get more comfortable with Readline.



Here’s the image:



Bash cheatsheet full version



The full set of versions is available here:

https://github.com/Athesto/cheatsheets



Features:

• Cursor and word movement

• Reverse/forward history search

• Kill/yank/transpose editing commands

• Ctrl, Meta (Alt/Opt), and Shift combos

• Color-coded categories

• Based on Readline defaults

• 4 progressive levels available in the repo



License (CC BY-SA 4.0):

You’re free to use, share, remix, or include this in teaching materials

(including commercial ones) as long as proper credit is given and derivative

works are shared under the same license. I wanted people to reuse it without

worrying about permissions.



Hope this helps anyone learning or teaching Bash!

Feedback and suggestions are very welcome.

https://redd.it/1phy40k
@r_bash
Help me on good shebang practice !!

as i knew that its a good practice to add shebang in the starting of noscript, i used it in all my projects. `#!/bin/bash` used it in my linutils and other repositories that depend on bash.


but now i started using NixOS and it shows bad interprator or something like that(an error).

i found about `#/usr/bin/env bash`

should i use it in all my repositories that need to run on debian/arch/fedora. i mean "is this shebang universally acceptable"

https://redd.it/1pi50s9
@r_bash
bash bash bash

idk pero hindi talaga ako nagagandahan don sa fAt!m@ A. na content creator galing sa tiktok 😭 ang oa niy for me. naiinis ako sa pag,umukha niya. ako lang ba like they aint cute bro they look like baliw


https://redd.it/1pi69xh
@r_bash
New or Old Bash guide

I see the bash tutorial in the side bar has a new version but the sub lists the old one. Which is recommended?

https://redd.it/1piqz4y
@r_bash
Why doesnt this command work on a mac?

Input

echo "Udemy - The AI Engineer Course 2025 Complete AI Engineer Bootcamp (8.2025)" | sed -E 's/\s+/-/g'

Output

Udemy - The AI Engineer Cour-e 2025 Complete AI Engineer Bootcamp (8.2025)


https://redd.it/1pivezi
@r_bash
I'm attempting to mimic multi-dimensional arrays for a personal use noscript. What I am currently doing is wrong and I can't seem to find a way to do it correctly.

\#List_out is an output of a func that generates surnames, traits and other information

\#List_out is currently a generated Surname
surnames+=("$List_out") #list of every surname

declare -a $List_out #list of connected items to the surname

\#List_out is now a first name connected to the most recently generated surname
eval "${surnames[-1\]}+=("$List_out")"

declare -A $List_out #name of individual (store characteristics)

\#List_out is now a chosen string and quirks is supposed to be the key for the associative array that was just defined
\#the second -1 refers to the last generated name in the array
eval "${{surnames[-1\]}[-1\]}[Quirks\]=$List_out"

If anyone has any suggestions I would be very grateful.

https://redd.it/1pjat85
@r_bash
noob Can simple noscript with mapfile be improved?

I have this simple noscript that finds empty directories recursively, opens a list of them with vim for user to edit (delete lines to omit from removal), then on save and exit, prints the updated list to prompt for removal.

Can the noscript be simplified? Open to all constructive criticism, however minor and nitpick, as well as personal preferences from experienced bash users.

Note: fd is not as standard as find command and I don't see the point of avoiding bashisms in the noscript since arrays were used anyway.

https://redd.it/1pjmqff
@r_bash
What the heck did I put in my bashrc?

I put this line in my .bashrc years ago:

bat () { echo "$(<"$@")" ; }

But I have been away from Linux since then. I tried it on my new installation (different distro) and get this error:

bash: "$@": ambiguous redirect

Anybody have any idea what I was thinking then?

https://redd.it/1pl635u
@r_bash
How does ${VARNAME@Q} ACTUALLY work

export SUFFIX="s/Mom/World/" && echo "Hello Mom" | sed ${SUFFIX@Q}

export SUFFIX="s/Mom/World/" && echo "Hello Mom" | sed "${SUFFIX}"

export SUFFIX="s/Mom/World/" && echo "Hello Mom" | sed "$(printf "%q" "$SUFFIX")"

Why does the first of these not work?

sed is receiving the ' characters in the ${SUFFIX@Q} one.

When exactly does it expand? How should I best think about this?

https://redd.it/1plbkq4
@r_bash
Script for 'cd-ing' into zip archives

Hey everyone!

I wrote this noscript to transparently allow for something like cd archive.zip.

I would appreciate constructive criticism on the function, as I have very little experience with bash noscripting and how it could be improved/what can go wrong. I recognize the background process is a little kludgy, but I wasn't sure how to do this without it.

#!/usr/bin/env zsh
# custom cd command allowing for transparent reading and writing of of zip
# archives.
function cd {
# if fuse-zip is not found, then use builtin cd
if ! command -v fuse-zip &>/dev/null; then
builtin cd "$@";
return "$?";
fi
local TARGET_FILE="$1";
if [[ "$#" == 0 || ! -f "$TARGET_FILE" ]]; then
builtin cd "$@";
return $?;
fi
local TARGET_FILE_EXTENSION="${TARGET_FILE:e}";
if [[ ! "$TARGET_FILE" =~ "apk|docx|epub|jar|pptx|pubx|xlsx|zip" ]]; then
builtin cd "$@";
return $?;
fi
if [[ ! -w "$TARGET_FILE" ]]; then
echo "Insufficient permissions to enter possible archive \"$TARGET_FILE\"" 1>&2;
return 1;
fi
echo "Attempting to enter possible archive \"$TARGET_FILE\"..." 1>&2;
local TARGET_FILE_PATH="$(realpath $TARGET_FILE)";
local FILE_NAME="${TARGET_FILE_PATH:t}";
# create a unique name for the stashed file
local TARGET_FILE_PATH_HASH="$(echo -n $TARGET_FILE_PATH | sha1sum | cut -d' ' -f1)";
# ensure stash exists
local STASH_DIR_PATH="$HOME/.zip_fuse_cache";
local STASH_FILE_PATH="$STASH_DIR_PATH/$TARGET_FILE_PATH_HASH-$FILE_NAME";
# prepare for mount
local MOUNT_POINT="$TARGET_FILE_PATH";
mv "$TARGET_FILE_PATH" "$STASH_FILE_PATH";
mkdir -p "$MOUNT_POINT";
# TODO: support other extensions:
# - tar
# - tar.gz
# - 7z
# - rar
case "$TARGET_FILE_EXTENSION" in
"apk" | "docx" | "epub" | "jar" | "pptx" | "pubx" | "xlsx" | "zip") # a large number of filetypes are actually zip archives in disguise
if ! fuse-zip "$STASH_FILE_PATH" "$MOUNT_POINT"; then
echo "\"$FILE_NAME\" not a valid $TARGET_FILE_EXTENSION file" 1>&2;
rmdir "$MOUNT_POINT";
mv "$STASH_FILE_PATH" "$TARGET_FILE_PATH";
return 1;
fi
builtin cd "$TARGET_FILE_PATH";
;;
*)
echo "Unsupported file type \"$TARGET_FILE_EXTENSION\"" 1>&2;
rmdir "$MOUNT_POINT";
mv "$STASH_FILE_PATH" "$TARGET_FILE_PATH";
return 1;
esac
echo "Stashed $TARGET_FILE at $STASH_FILE_PATH" 1>&2;
# background process to monitor for file closing
echo "Monitoring for unmount at process: " 1>&2;
(
cd "$HOME";
while fuser -m "$MOUNT_POINT" &>/dev/null ; do
sleep 3;
done
fusermount -u "$MOUNT_POINT";
# ensure fuse-zip finishes writing
sleep 1;
while ps aux | grep -q "[f]use-zip.*$STASH_FILE_PATH"; do
sleep 0.5;
done
rmdir "$MOUNT_POINT";
mv "$STASH_FILE_PATH" "$TARGET_FILE_PATH";
exit 0;
) &
disown;
return 0;
}


I also have the following in my zshrc in case the background process is somehow interrupted:
#!/usr/bin/env zsh

# checks the .zip_fuse_cache used by .dotfiles/zsh/.config/zsh/functions/cd for
# orphaned files, and alerts the user of any if found.

if [[ -n "$(ls $HOME/.zip_fuse_cache)" ]]; then
echo "Files detected in $HOME/.zip_fuse_cache." 1>&2;
echo "This indicates possible corruption of archives." 1>&2;
echo "Please check the following files: " 1>&2;
echo "$(ls -A $HOME/.zip_fuse_cache/)";
fi


https://redd.it/1pl6gsb
@r_bash
Recursive file renaming based on parent directory

I have some ripped audiobooks that are currently structured as

/book
/disc 1
/track 1.mp3, track 2.mp3
/disc 2
/track 1.mp3, track 2.mp3

and I need to rename and move the tracks to follow this structure

/book
/disc 01 - track 1.mp3,disc 01 - track 2.mp3, disc 02 - track 1.mp3, disc 02 - track 2.mp3

I know I can use mv to do part of this i.e. for f in *.mp3; do mv "$f" "CD 1 - $f"; done but how do I make it name based on the folder it is in and make it recursive?


Thank yall

https://redd.it/1pluwfp
@r_bash
Automate the initial creation process of your bash noscript

Tired of the initial hassle of creating a Bash noscript—like making the file readable and executable? If so, this tool is for you.

https://github.com/Keys02/noscriptify

PS: noscriptify also adds the shebang line.

All contributions are welcome

https://redd.it/1pm5vaw
@r_bash
Concurrent, parallel, or simultaneous?

I frequently write noscripts that should only have 1 instance running at a time. For instance, a noscript that copies a MySQL table from 1 host to another.

I implement this with a snippet like:

# prevent simultaneous execution                                                                                                                                             
pids=$(pidof -o '%PPID' -x "$(basename "$0")")
if [[ -n "${pids}" ]]
then
echo "$(basename $0) (${pids}) is already running."
exit
fi

Would you consider the second instance of this noscript to be concurrent, parallel, or simultaneous?

https://redd.it/1pmte90
@r_bash
Bash noscript for docker monitoring

I wanted to monitor and manage docker containers on a few servers. All the solutions I found were either heave or were missing things which I wanted so I started developing my own bash noscript - it started as a simple noscript but after many imitations and improvements based on usage it has become a real helpful tool.

Just wanted to share here in appreciation of Bash - there is so much which I did not even know can be done with simply bash noscripting.

https://github.com/buildplan/container-monitor

https://redd.it/1pnlqlx
@r_bash
change color in css file (working)

i have this simple bash file, to run you do for example "./test.sh accent \\#ffffff", but i want to merge the functions into one. how to do this?

https://preview.redd.it/87w1mp1q6g7g1.png?width=1281&format=png&auto=webp&s=c510c57cc1727e1e94613841bb6dd5281da41d74



https://redd.it/1pnloa1
@r_bash
Asking for help with a command launcher noscript

I'd like to ask a question about an automation strategy which has eluded me.

# What I'm trying to do

I'd like to have a noscript which:

1. can launch a new terminal emulator
2. then run a login shell in the terminal emulator (with all my personal shell initialization)
3. can then run an arbitrary program or command of my choosing
4. then on completion or termination of the program the shell stays alive and interactive
5. also the arbitrary command is added to shell history

Hopefully I explained that well.
Unfortunately something like alacritty -e bash -c 'echo hello' does not fulfill these requirements.
With the above the terminal is closed after program completion and is not run with shell initialization (login shell).

I'll share my solution, but I'm curious if there is an easier way to accomplish the same:

# Current Solution

I also put the code in this repo

I add the following to the end my ~/.bashrc

if [ -n ${INIT_CMD} ]; then
print -s "${INITCMD}"
eval "${INIT
CMD}"
unset INITCMD
fi

then to launch programs I use something like:

#!/usr/bin/env bash

# terminal='alacritty'
# terminal='ghostty'
# terminal='st'
terminal='kitty'

${terminal} -e
$SHELL \
-c 'INIT
CMD="echo hello" $SHELL'

where echo hello is the "program"

Which does require starting up two shells, however, the first shell with -c flag is cheap. The second shell is the login shell.

Thanks in advance if you know a simpler way to accomplish this!

https://redd.it/1po6z4y
@r_bash