Your .bashrc modifications and additions

No aliases or functions! What adjustments did you do to your ~/.bashrc file? I’ve searched the forum, but couldn’t find a post with this topic. I even didn’t know where to put it under.

One thing I want to share is the ability to expand aliases with a specific key combination. This is very useful to me, being able to edit the alias in case of some temporary modification or just to see what it was. I use this quite often.

# Expand alias with key binding "Control+Space".
bind '"\C- ": alias-expand-line'
1 Like

I basically wrote a bunch of shell functions in a script that I placed inside /etc/profile.d. Here’s a snippet of that script:

activate_bash_bindings() {
    # Define keybindings
    bind -x '"\ef": fzf_select_from global'
    bind -x '"\ew": fzf_select_from cwd'
    bind -x '"\eh": fzf_cmd_history'
    bind -x '"\et": new_alacritty_instance_in_cwd'
    bind -m emacs-standard '"\ec": "\C-u fzf_cd cwd\C-m"'
    bind -m emacs-standard '"\ed": "\C-u fzf_cd global\C-m"'
    bind -m emacs-standard '"\er": "\C-u cd_into_project_root\C-m"'
    bind -m emacs-standard '"\ev": "\C-u nvim_in_cwd\C-m"'
    bind -m emacs-standard '"\em": vi-movement-mode'
    bind -m emacs-standard '"\eg":' # Turn off Alt-g glob completion
    bind -m emacs-standard '"\e\t": glob-complete-word'
    bind -m vi '"\em": emacs-editing-mode'
    bind -m vi-insert '"\em": emacs-editing-mode'
}

# All other shell functions used inside activate_bash_bindings() goes here...
fzf_cd() {
    # fzf integration for changing working directories
}

fzf_cmd_history() {
    # fzf integration for search bash history
}

export -f activate_bash_bindings
export -f fzf_cd
export -f fzf_cmd_history

For any user that wants to use these bindings, I simply add a line to call activate_bash_bindings() inside that user’s .bashrc

1 Like

I only need a single line in mine:

zsh

That takes care of everything for me. :rofl:

9 Likes

That’s an interesting approach. Has this an advantage over just sourcing an external script? Like ~/.bashrc_functions and then the user just source it with . ~/.bashrc_functions .

@dalto I never saw anyone doing this. Wouldn’t it interfere with scripts or so? Or when I execute scripts with bash script.sh in example. I guess not, otherwise you wouldn’t do it. :smiley: I personally did set the default shell in the terminal instead (when I was using zsh).

So that those functions are sourced only once during user login. If you source those functions inside .bashrc, the sourcing will take place every time you start an interactive non-login shell.

1 Like

Two things:

  • No, it won’t interfere with scripts because those don’t source your .bashrc.
  • That was a joke, I don’t actually do that. :sweat_smile:
6 Likes

This is one setting that I typically add to ~/.bashrc:

export FUNCNEST=100

It helps preventing long lasting loops in bash scripts.

For example:

LoopingFunction() { LoopingFunction; }

would cause trouble without the FUNCNEST setting.

1 Like

I’ll share two lines from my .bashrc.

# very important!
export FROG=$'\U1F438'

I normally use Zsh. My .zshrc also has those two lines.

6 Likes

Not gonna lie, I was expecting yours to be something along the lines of:

# EXTREMELY important!
[ "$XDG_SESSION_TYPE" = "wayland" ] && nuke

(Where nuke is the obvious command for those who know, and the safe command for those who don’t know :stuck_out_tongue: )

1 Like

Interesting. I never encountered a problem with a script due to this specific issue of function recursion going too deep. Is this just to prevent this from happening ever or did you encounter such a script that made you adding this setting? At least someone who really needs it for the script, could overwrite the variable beforehand to make sure the function runs as intended (say a benchmark or a solution like in Haskell).

I don’t think we talk about malicious scripts by design, but more of a mistake. Because it would be easy to change the FUNCNEST before executing the function recursion loop.

It has been useful when writing and testing scripts. So yes, mostly for preventing bugs to escalate.

However, some malicious fork bomb scrips have been published too. If one happens to copy/paste such a thing, even a small, seemingly innocent script, problems will occur.

1 Like

Using the BASH_ENV environment variable can somewhat circumvent this, but only to a limited extent. One could add a custom script with the following lines:

export FUNCNEST=100
readonly FUNCNEST

And then assign the path of that script to BASH_ENV. The caveat is that we have to run scripts by invoking another bash instance instead of running them directly (e.g: bash -c some-command) for the script referenced in BASH_ENV to be sourced.

This approach is quite limited as well.

$ bash -c ./scriptX

FUNCNEST cannot be reassigned inside scriptX but if scriptX invokes a second script, scriptY, FUNCNEST can still be changed inside scriptY since the readonly property isn’t inherited by child processes.

2 Likes
# do not save the following commands in .bash_history
HISTIGNORE="?:??:cd*:history*:man *:exit:reboot:poweroff:sudo*:truecrypt -P*"
2 Likes

This is my bashrc

alias ls='ls --color=auto'
alias grep='grep --color=auto'
if [[ ${EUID} == 0 ]] ; then
	PS1='\[\033[01;31m\][\h\[\033[01;36m\] \W\[\033[01;31m\]]\$\[\033[00m\] '
else
	PS1='\[\033[01;32m\][\u@\h\[\033[01;37m\] \W\[\033[01;32m\]]\$\[\033[00m\] '
fi

export HISTFILESIZE=2000
export HISTSIZE=1000

the alias is a left over from my endeavour install
PS1 is for bash prompt colors

I’m not sure what this is doing?

If not running interactively, don't do anything
[[ $- != *i* ]] && return (also left over from the installer)
1 Like

To understand what this line is doing, you have to take into account two things: (1) “short-circuit” evaluation of logical operations; and (2) the meaning of $-

Short-circuit evaluation is a common way in which programming languages handle logical AND and OR operations. For an AND operation to evaluate to true, both operands must also evaluate to true. If even one of the operand evaluates to false, then we can deduce (from the definition of the AND operation) that the operation must yield false without needing to evaluate the second operand. Now apply this understanding to the line in question.

[[ $- != *i* ]] && return 

This basically means that the return statement will only be executed if and only if the test condition [[ $- != *i*]] evaluates to true. If [[ $- != *i* ]] evaluates to false, the return statement will be skipped due to the short-circuit evaluation described above.

$- is a special variable in bash. It is basically a string containing option flags for the current shell session. For example, if $- is himBHs, then it means the current shell has the hashall option set (h), is running in interactive mode (i), has the monitor mode set (m), has brace expansion enabled (B), has history expansion enabled (H), and allows you to source commands from stdin (s).

Combining everything together, it should be obvious now what that line does. Due to the return command, everything following that line will not be executed if [[ $- != *i* ]] evaluates to true (the shell isn’t interactive).

2 Likes

Very nice explanation! I learned something new today about this $- Bash variable. Good to have in mind.

So this variable is about the mode of the shell. Compared to the other (way more known) way of checking if the stdin or stdout is in a terminal or not:

 if [ -t 0 ] ; then
    echo stdin is a terminal
 fi

But I think checking for $- variable is a much more reliable way. Or does it even matter?

Thanks for your explanation!
I do programming myself but in php so i don’t know much about bash

As $- isn’t set anywhere in bashrc anymore (i removed it) the line basically doesn’t do anything so can be removed?

Yeah, that line doesn’t really do anything since .bashrc won’t be sourced when you run a non-interactive shell anyway.

Edit:

@fred666 Please note that my previous statement is wrong. It turns out that I didn’t read the section on remote invocation in Bash’s manual, which states that:

Also, when you have BASH_ENV set to: 1) the path of your .bashrc; or (2) the path of another script that sources your .bashrc

A potential use case for this is perhaps you don’t want someone to execute your .bashrc as a shell script. E.g:

$ ./.bashrc

or

$ bash -c './.bashrc'

Having the [ $- != *i* ] && return check does indeed prevent the .bashrc from running for those two use cases. Although I can’t image why anyone would want to run a .bashrc file in that manner.

It depends on your intent. If the intent is to reliably test whether a script is being run inside an interactive shell, then the $- method is indeed much more reliable.

The [ -t 0] method, on the other hand, is not a reliable predictor of shell interactivity because a script can be running inside a non-interactive shell and still have its stdin connected to a terminal. The fact that the script’s stdin is connected to a terminal does not necessarily mean that it is running in an interactive shell.

Create a shell script like this:

if [ -t 0]; then
    echo "Stdin connected to terminal"
else
    echo "Stdin not connected to terminal"
fi

echo "$-"

If you execute the script normally, it will always be non-interactive, yet the stdin of that script is still connected to a terminal.

$ ./script.sh
Stdin is connected to terminal.
hB

Unless you pipe something into it, which obviously affects the [ -t 0 ] test because the stdin is now connected to the stdout of a command rather than the terminal.

$ cat somefile | ./script.sh
Stdin not connected to terminal.
hB

Only the $- variable correctly indicates shell interactivity in this case.

1 Like

Most important for me is the setting

# append to the history file, verify history substitutions
shopt -s histappend histverify

because I use !$ on the command line a lot.

Also, on the subject of history, I have

# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth

# append to the history file, verify history substitions
shopt -s histappend histverify

# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=2000
HISTFILESIZE=5000

# this ignores single-word commands
HISTIGNORE=$'*([\t ])+([-%+,./0-9\:@A-Z_a-z])*([\t ])'

# save history files for each tmux pane in separate files
if [[ $TMUX_PANE ]]; then
  HISTFILE=$HOME/.bash_history_tmux_${TMUX_PANE:1}
fi

in there for convenience.

1 Like

for the history, I have following:

# Ignore duplicates in history file.
export HISTCONTROL=ignoreboth:erasedups

Why do you not log single word commands into history? I know its a personal setting for you, just asking (hopefully I don’t sound too snarky or like that).

Thanks to you I’m digging into shopt options now and learn bunch of new ways to customize. Never heard of histverify before. There is also expand_aliases, but it does not work for me (or I misunderstand what it is). (Edit: Never mind. expand_aliases is just there to make aliases working the way it is working by default. Without this option aliases are just disabled.) https://www.gnu.org/software/bash/manual/html_node/The-Shopt-Builtin.html