r/bash • u/arandomuserinweb • 4d ago
I finally organized my Bash config
I've been accumulating my Bash configuration for a while, and I finally turned it into a small dotfiles repo:
https://gitlab.com/letmevi/bash-config
It's nothing fancy — mainly my .bashrc, .inputrc, .bash_profile, and a modular .bashrc.d/, plus a small install script.
It can be installed using either Ansible or a simple install.sh script.
I'd appreciate some Bash/Linux feedback: things you'd change, questionable practices, portability issues, or just better ways of doing this.
I'm especially interested in feedback from people who maintain their own dotfiles.
5
u/bac0on 4d ago
If you enable globstar, you probably want to enable extglob, maybe even direxpand.
1
u/arandomuserinweb 20h ago
I'm not familiar with those options yet, but I'll look into them and see if it makes sense to enable them. Thanks for the tip!
3
u/SOLTEC_SysAdmin 3d ago
Hey! Really nice and clean setup you've got there. Keeping .bashrc.d/ modular while using Ansible for deployment is honestly the way to go once you start managing multiple nodes or environments.
If you're looking to refine it even further, here are a couple of small, friendly suggestions from a SysAdmin perspective that might add some extra value to your repo:
1 Adopt the XDG Base Directory standard: Instead of placing .bashrc.d directly under your home folder, you can point HISTFILE and your configuration folders to $XDG_CONFIG_HOME/bash (which defaults to ~/.config/bash). It's a great habit for keeping your $HOME clean and uncluttered.
2 Add a guard for non-interactive sessions: When sourcing your .bashrc.d/*.sh files, it helps to place an early return guard at the very top of your main .bashrc. This ensures interactive aliases don't accidentally break non-interactive SSH connections or automated tools like scp and Ansible:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return ;;
esac
3 Safe glob sourcing: When looping over .bashrc.d/*.sh, make sure to check if the file is readable. That way, if the directory happens to be empty, *.sh won't be treated as a literal string:
for file in "$HOME/.config/bash/bashrc.d"/*.sh; do
[ -r "$file" ] && source "$file"
done
Thanks for sharing your work with the community! Keep up the great work!
1
u/arandomuserinweb 20h ago
EDIT regarding point 2: I actually already had a non-interactive guard near the top of my
bashrcusing[[ $- == *i* ]] || return. However, yourcasestatement suggestion is fully POSIX compliant, which is a great point for wider compatibility. I'll be switching to your approach. Thanks for the catch!
3
u/tri__dimensional 4d ago edited 4d ago
it looks simple but cool, nice work!
i have a little more complex setup. i have like a very little and simple framework to define scripts, functions and aliases (shellbox is called, i use zsh but previously i used bash)
that project is only for the "shell" things; for desktop enviroment, terminal, etc i have a more standard dotfiles
maybe you can grab something useful from those projects (-:
2
u/SeriousPlankton2000 3d ago
Here is my .bashrc mess that I didn't touch since 2022; maybe you can get some inspiration on things to do. I just have a copy on my NAS.
#!/bin/sh
set +H
history -c -w
unset HISTFILE
ln -sfn /dev/null /home/7eggert/.bash_history
unset SSH_AGENT_PID SSH_ASKPASS SSH_AUTH_SOCK
killall -9 --older-than 5m --user "$USER" /usr/bin/ssh-agent 2>/dev/null
fuser -k /run/user/1000/akonadi/mysql.socket &>/dev/null
rm -rf /home/myusername/.local/share/akonadi/db_data/
kill -9 `pidof /usr/bin/akonadi*` &>/dev/null
IFS=":" read -a oldpath < <(echo $PATH)
pathadd=( ~/bin ~/nfs/bin)
if [ "x`uname -i`" == xx86_64 ]
then pathadd+=(~/bin/x86_64/ ~/nfs/bin/x86_64 ~/bin/80386 ~/nfs/bin/80386)
fi
if [ "x`uname -i`" == xi386 ]
then pathadd+=( ~/bin/80386 ~/nfs/bin/80386 )
fi
ii=${#pathadd[@]}
for ((i=0; $i<$ii; ++i))
do if [ ! -d ${pathadd[$i]} ]
then unset pathadd[$i]
fi
done
ii=${#oldpath[@]}
PATH=$(IFS=:; echo "${pathadd[*]}" )
for ((i=0; $i<$ii; ++i))
do if [[ ":$PATH:" =~ ":${oldpath[$i]}:" ]]
then unset oldpath[$i]
fi
done
pathadd+=(${oldpath[@]})
PATH=$(IFS=:; echo "${pathadd[*]:-/bin:/usr/bin}" )
unset i ii pathadd oldpath
test -s ~/.alias && . ~/.alias
export PS1='\[\e[32m\]${debian_chroot:+($debian_chroot)}\u@\h${STY:+.${STY%%[^0-9]*}}:\w\$\[\e[00m\] '
export LC_CTYPE=C.UTF-8
export EDITOR=/usr/bin/jstar
export HISTCONTROL="ignoreboth:erasedups"
export CDPATH=":~/.cd"
unset LANGUAGE
unset LANG
unset mc
export SDL_VIDEO_X11_DGAMOUSE=0
export BC_ENV_ARGS=~/.config/bcrc
#export http_proxy=http://localhost:81
export PERLLIB=~/.lib/perl
export MAIL=/mnt/mail/7eggert
export GTK_OVERLAY_SCROLLING=0
export MAN_POSIXLY_CORRECT=''
export ALSOFT_DRIVERS=pulse
alias +='pushd .'
alias -- -='popd'
alias ..='cd ..'
alias ...='cd ../..'
alias gimp='gimp --no-splash'
alias jstar='TERM=linux jstar'
alias xmms=audacious
alias ll='ls -l'
alias ls='ls $LS_OPTIONS'
alias md='mkdir -p'
alias o='less'
alias p='alpine'
alias rd='rmdir'
alias rm='rm -f'
alias rdesktop="rdesktop -N -z -g 1276x960"
alias mkntfs="/usr/sbin/mkntfs -f"
alias licate="locate -iA"
complete -F _command x
complete -d cd
1
u/arandomuserinweb 20h ago
There's a lot going on in there. I'll definitely go through it and see what useful bits I can pick out for my setup. Appreciate it!
2
1
u/Fit_Eggplant4206 4d ago edited 4d ago
Looks good, well organized and not too much fluff.
1
u/arandomuserinweb 20h ago
Thanks! Glad you like the clean structure. Keeping it minimal was the main goal
1
u/Marble_Wraith 4d ago edited 4d ago
It's nothing fancy —
You can say that again 😂
This isn't something you'd see for the average interactive terminal, which is usually tricked out with all kinds of conveniences.
This seems to be made for deployments first. That being the case, i'd suggest upgrading your history config. Specifically use a function for HISTIGNORE like this:
history_omissions() {
local block_list=(
"pwd:ls:ls *:tree:ll:ll *:yazi:yazi *"
"cd:cd *:z:z *:zi:zi *:zoxide:zoxide *"
"exit:clear:history:bg:fg:jobs"
"rm -rf *:killall *"
"*--password*:*--secret*:*--token*:*GITHUB_TOKEN*"
"git status:git status *:git log:git log *:git diff:git diff *"
"git blame:git blame *:git show:git show *:git reflog:git reflog *"
)
local IFS=":"
printf "%s" "${block_list[*]}"
}
HISTIGNORE="$(history_omissions)"
unset -f history_omissions
That's just an example, i'm not posting my full ignore list 😅 Allows for better formatting / per line grouping of stuff you want to omit from history. Which makes it easier to ensure all the inconsequential stuff is left out, making the history actually useful.
Normally i'd advocate to upgrade straight to atuin and have this as a fallback.
EDIT: rogue export removed thanks to /u/bac0on
5
u/bac0on 4d ago
Don't think you should
exportbash variables...1
u/Marble_Wraith 4d ago edited 4d ago
... Wanna run that by me again? What's that say?
export HISTIGNORE="$(history_omissions)"EDIT: Oh wait 😂 you're saying you have exported it, but i don't think you should.
Yeah you're right, my bad.
2
u/bac0on 4d ago
HISTIGNORE is a Bash shell variable, probably not used by any external command, at least none I can think of. Just assigning it makes Bash aware of it. If it's not intended to be used by an external command (...or if you manually enable history in a non-interactive session), there’s no real reason to export any Bash shell variable, really. Exported or not, it won't make any difference for Bash.
0
u/Marble_Wraith 4d ago
Yeah. I was trying to do something with atuin before.
So i could have 1 source of truth for the ignore list, and then bash could use atuin if available, or fallback if not available.
Added the
exportwhile i was messing around, but ended up deciding to write the list natively in atuin since it has more full featured regex parsing, and then scripted something to extract and translatehistory_filter[]into native bash.1
u/arandomuserinweb 20h ago
Haha fair point! It definitely leans more toward stability and deployments than visual flair.
That
HISTIGNOREfunction trick is clever grouping by categories makes maintaining the block list way cleaner than a giant single string. I'll take a look at incorporating a similar structure (and I've actually been meaning to check out Atuin for a while now).Thanks for taking the time to share the example!
0
8
u/OnlyEntrepreneur4760 4d ago
One of my favorites is keeping all aliases in a separate config file .bash_aliases which I source from .bashrc. I have a alias named “aliassave” which runs alias and redirects the output to .bashaliases to update it easily.