Next few lines of code:
if [ -z "$print" ]; then
fi
Here we check whether our $print
variable is empty. If it is, then we print a series of instructions which tell the user which config file to add shell completions to, and what code to add to that file. The code for constructing those instructions and code is below.
Identifying the User’s Shell Config File
The first block of code inside the if
statement is:
case "$shell" in
bash )
if [ -f "${HOME}/.bashrc" ] && [ ! -f "${HOME}/.bash_profile" ]; then
profile='~/.bashrc'
else
profile='~/.bash_profile'
fi
;;
zsh )
profile='~/.zshrc'
;;
ksh )
profile='~/.profile'
;;
fish )
profile='~/.config/fish/config.fish'
;;
* )
profile='your profile'
;;
esac
This case
statement is pretty long, but it actually doesn’t do much. Its only job is to check the "$shell"
variable that we set earlier, and set a variable named profile
depending on what the user’s shell is.
The value we set for profile
is a path to the user’s shell configuration file, or the string "your profile"
if none of the 4 supported shells were detected.
3 of the 4 shells (zsh
, ksh
, and fish
) are straightforward- we directly set profile
to a hard-coded filepath.
The case statement for Bash, however, is marginally more complex:
bash )
if [ -f "${HOME}/.bashrc" ] && [ ! -f "${HOME}/.bash_profile" ]; then
profile='~/.bashrc'
else
profile='~/.bash_profile'
fi
;;
If our shell is “bash”, we run another if/else
check. We first check whether the ~/.bashrc
corresponds to an existing file:
[ -f "${HOME}/.bashrc" ]
If that file exists, we then check whether ~/.bash_profile
does not correspond to an existing file. If this condition is true, we set the profile
variable equal to ~/.bashrc
.
If either of these tests are false, we set profile
equal to ~/.bash_profile
.
The catch-all, default case branch:
* )
profile='your profile'
;;
This just sets profile
equal to the string "your profile"
. We’ll find out why it does this in the next block of code.
Printing The Instructions
Next lines of code:
{ echo "# Load rbenv automatically by appending"
echo "# the following to ${profile}:"
echo
case "$shell" in
fish )
echo 'status --is-interactive; and rbenv init - fish | source'
;;
* )
printf 'eval "$(rbenv init - %s)"\n' "$shell"
;;
esac
echo
} >&2
Here we take everything inside the curly braces, and we send the output to stderr
.
The content of the data we send is a message telling the user what code to add to their shell configuration file (i.e. ~/.zshrc
, ~/.profile
, etc., depending on their shell).
If we call rbenv init
and specify fish
as our shell, we see:
$ rbenv init fish
# Load rbenv automatically by appending
# the following to ~/.config/fish/config.fish:
status --is-interactive; and rbenv init - fish | source
We see that profile
evaluates to ~/.config/fish/config.fish
, as we expected from the hard-coded value in our earlier case
statement.
If we specify Bash, we see:
$ rbenv init bash
# Load rbenv automatically by appending
# the following to ~/.bash_profile:
eval "$(rbenv init - bash)"
Specifying zsh
results in:
$ rbenv init zsh
# Load rbenv automatically by appending
# the following to ~/.zshrc:
eval "$(rbenv init - zsh)"
When the user specifies a shell other than one that RBENV supports, the string the following to ${profile}:
evaluates to the following to your profile:
:
$ rbenv init foobar
# Load rbenv automatically by appending
# the following to your profile:
eval "$(rbenv init - foobar)"
The printf
command
We saw that the eval
command is almost identical for the output of rbenv init bash
and rbenv init zsh
. The only difference is that the name of the shell has changed. That’s because we dynamically interpolated the value of "$shell"
into the string, using the printf
command:
printf 'eval "$(rbenv init - %s)"\n' "$shell"
Running man printf
in the terminal returns the following:
PRINTF(1) General Commands Manual PRINTF(1)
NAME
printf – formatted output
SYNOPSIS
printf format [arguments ...]
DESCRIPTION
The printf utility formats and prints its arguments, after the first, under control of the format. The format is a character string which contains three
types of objects: plain characters, which are simply copied to standard output, character escape sequences which are converted and copied to the standard
output, and format specifications, each of which causes printing of the next successive argument.
The arguments after the first are treated as strings if the corresponding format is either c, b or s...
The above man
entry is saying that the first argument to printf
is the format you want your output to take, and the remaining argument(s) are passed to that format string.
In our code:
- The string
'eval "$(rbenv init - %s)"\n'
is the format, and - The value of the
"$shell"
variable is the one and only argument.
In our format argument, we substitute the %s
syntax means with the value of "$shell"
variable. This passing in of one string to another is called “string interpolation”.
The s
in %s
just means that we’ll be passing in a string. We can also tell printf
to expect numbers:
$ printf "There are %d orders valued at over %d euros.\n" 64 1500
There are 64 orders valued at over 1500 euros.
It can even convert hexadecimal numbers for us:
$ printf "0xf as a human-readable number is %d.\n" 0xF
0xf as a human-readable number is 15.
Exiting early
The last line of code inside the if
block is just an exit statement:
...
exit 1
fi
The non-zero exit code tells us that running rbenv init
without -
(which is how we ended up inside the if
-block) is a sad-path case.
Let’s move on.