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'
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. 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.
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.
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.
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).
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?
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.
# 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
# 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