Create an account


Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Fedora - Customizing Bash

#1
Customizing Bash

<div style="margin: 5px 5% 10px 5%;"><img src="https://www.sickgaming.net/blog/wp-content/uploads/2020/07/customizing-bash.png" width="1024" height="711" title="" alt="" /></div><div><p>The outermost layer of your operating system – the part you interact with – is called the <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/Shell_(computing)" target="_blank" rel="noreferrer noopener">shell</a>. Fedora comes with several preinstalled shells. Shells can be either graphical or text-based. In documentation, you will often see the acronyms GUI (Graphical User Interface) and CLI (Command-Line Interface) used to distinguish between graphical and text-based shells/interfaces. Other <a aria-label="undefined (opens in a new tab)" href="https://fedoramagazine.org/fedoras-gaggle-of-desktops/" target="_blank" rel="noreferrer noopener">GUI</a> and <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/Comparison_of_command_shells" target="_blank" rel="noreferrer noopener">CLI</a> shells can be used, but <a href="https://en.wikipedia.org/wiki/GNOME" target="_blank" rel="noreferrer noopener">GNOME</a> is Fedora’s default GUI and <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)" target="_blank" rel="noreferrer noopener">Bash</a> is its default CLI.</p>
<p> <span id="more-31147"></span> </p>
<p>The remainder of this article will cover recommended dotfile practices for the Bash CLI.</p>
<h2>Bash overview</h2>
<p>From the Bash reference manual:</p>
<blockquote class="wp-block-quote">
<p>At its base, a shell is simply a macro processor that executes commands. The term macro processor means functionality where text and symbols are expanded to create larger expressions.</p>
<p><cite>Reference Documentation for Bash<br />Edition 5.0, for Bash Version 5.0.<br />May 2019</cite></p></blockquote>
<p>In addition to helping the user start and interact with other programs, the Bash shell also includes several built-in commands and keywords. Bash’s built-in functionality is extensive enough that it is considered a <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/High-level_programming_language" target="_blank" rel="noreferrer noopener">high-level programming language</a> in its own right. Several of Bash’s keywords and operators resemble those of <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/C_(programming_language)" target="_blank" rel="noreferrer noopener">the C programming language</a>.</p>
<p>Bash can be invoked in either interactive or non-interactive mode. Bash’s interactive mode is the typical terminal/command-line interface that most people are familiar with. <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/GNOME_Terminal" target="_blank" rel="noreferrer noopener">GNOME Terminal</a>, by default, launches Bash in interactive mode. An example of when Bash runs in non-interactive mode is when commands and data are <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/Pipeline_(Unix)" target="_blank" rel="noreferrer noopener">piped</a> to it from a file or shell script. Other modes of operation that Bash can operate in include: login, non-login, remote, POSIX, unix sh, restricted, and with a different UID/GID than the user. Various combinations of these modes are possible. For example interactive+restricted+POSIX or non-interactive+non-login+remote. Which startup files Bash will process depends on the combination of modes that are requested when it is invoked. Understanding these modes of operation is necessary when modifying the startup files.</p>
<p>According to the Bash reference manual, Bash …</p>
<blockquote class="wp-block-quote">
<p>1. Reads its input from a file …, from a string supplied as an argument to the -c invocation option …, or from the user’s terminal.</p>
<p>2. Breaks the input into words and operators, obeying [its] quoting rules. … These tokens are separated by metacharacters. Alias expansion is performed by this step.</p>
<p>3. Parses the tokens into simple and compound commands.</p>
<p>4. Performs the various shell expansions …, breaking the expanded tokens into lists of filenames … and commands and arguments.</p>
<p>5. Performs any necessary redirections … and removes the redirection operators and their operands from the argument list.</p>
<p>6. Executes the command.</p>
<p>7. Optionally waits for the command to complete and collects its exit status.</p>
<p><cite>Reference Documentation for Bash<br />Edition 5.0, for Bash Version 5.0.<br />May 2019</cite></p></blockquote>
<p>When a user starts a terminal emulator to access the command line, an interactive shell session is started. GNOME Terminal, by default, launches the user’s shell in non-login mode. Whether GNOME Terminal launches the shell in login or non-login mode can be configured under <em>Edit</em> → <em>Preferences</em> → <em>Profiles</em> → <em>Command</em>. Login mode can also be requested by passing the <em>–login</em> flag to Bash on startup. Also note that Bash’s <em>login</em> and <em>non-interactive</em> modes are not exclusive. It is possible to run Bash in both <em>login</em> and <em>non-interactive</em> mode at the same time.</p>
<h2>Invoking Bash</h2>
<p>Unless it is passed the <strong><em>—</em></strong><em>noprofile</em> flag, a Bash login shell will read and execute the commands found in certain initialization files. The first of those files is <em>/etc/profile</em> if it exists, followed by one of <em>~/.bash_profile</em>, <em>~/.bash_login</em>, or <em>~/.profile</em>; searched in that order. When the user exits the login shell, or if the script calls the <em>exit</em> built-in in the case of a non-interactive login shell, Bash will read and execute the commands found in <em>~/.bash_logout</em> followed by <em>/etc/bash_logout</em> if it exists. The file <em>/etc/profile</em> will normally source <em>/etc/bashrc</em>, reading and executing commands found there, then search through <em>/etc/profile.d</em> for any files with an <em>sh</em> extension to read and execute. As well, the file <em>~/.bash_profile</em> will normally source the file <em>~/.bashrc</em>. Both <em>/etc/bashrc</em> and <em>~/.bashrc</em> have checks to prevent double sourcing.</p>
<p>An interactive shell that is not a login shell, will source the <em>~/.bashrc</em> file when it is first invoked. This is the usual type of shell a user will enter when opening a terminal on Fedora. When Bash is started in non-interactive mode – as it is when running a shell script – it will look for the <em>BASH_ENV</em> variable in the environment. If it is found, will expand the value, and use the expanded value as the name of a file to read and execute. Bash behaves just as if the following command were executed:</p>
<pre class="wp-block-preformatted">if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi</pre>
<p>It is important to note that the value of the <em>PATH</em> variable is not used to search for the filename.</p>
<h2>Important user-specific dotfiles</h2>
<p>Bash’s best-known user dotfile is <em>~/.bashrc</em>. Most user customization is done by editing this file. Most user customization, may be a stretch since there are reasons to modify all of the mentioned files; as well as other files that have not been mentioned. Bash’s environment is designed to be highly customizable in order to suit the needs of many different users with many different tastes.</p>
<figure class="wp-block-image size-large"><img src="https://www.sickgaming.net/blog/wp-content/uploads/2020/07/customizing-bash.png" alt="" class="wp-image-31367" /></figure>
<p>When a Bash login shell exits cleanly, <em>~/.bash_logout</em> and then <em>/etc/bash_logout</em> will be called if they exist. The next diagram is a sequence diagram showing the process Bash follows when being invoked as an interactive shell. The below sequence is followed, for example, when the user opens a terminal emulator from their desktop environment.</p>
<figure class="wp-block-image size-large"><img src="https://www.sickgaming.net/blog/wp-content/uploads/2020/07/customizing-bash-6.png" alt="" class="wp-image-31368" /></figure>
<p>Armed with the knowledge of how Bash behaves under different invocation methods, it becomes apparent that there are only a few typical invocation methods to be most concerned with. These are the non-interactive and interactive login shell, and the non-interactive and interactive non-login shell. If global environment customizations are needed, then the desired settings should be placed in a uniquely-named file with a <em>.sh</em> extension (<em>custom.sh</em>, for example) and that file should be placed in the <em>/etc/profile.d</em> directory.</p>
<p>The non-interactive, non-login invocation method needs special attention. This invocation method causes Bash to check the <em>BASH_ENV</em> variable. If this variable is defined, the file it references will be sourced. Note that the values stored in the <em>PATH</em> environment variable are not utilized when processing <em>BASH_ENV</em>. So it must contain the full path to the file to be sourced. For example, if someone wanted the settings from their <em>~/.bashrc</em> file to be available to shell scripts they run non-interactively, they could place something like the following in a file named <em>/etc/profile.d/custom.sh</em> …</p>
<pre class="wp-block-preformatted"># custom.sh
.
.
.
#If Fedora Workstation
BASH_ENV="/home/username/.bashrc"
.
.
.
#If Fedora Silverblue Workstation
BASH_ENV="/var/home/username/.bashrc" export BASH_ENV</pre>
<p>The above profile drop-in script will cause the user’s <em>~/.bashrc</em> file to be sourced just before every shell script is executed.</p>
<p>Users typically customizie their system environment so that it will better fit their work habits and preferences. An example of the sort of customization that a user can make is an alias. Commands frequently run with the same set of starting parameters are good candidates for aliases. Some example aliases are provided in the <em>~/.bashrc</em> file shown below.</p>
<pre class="wp-block-preformatted"># .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then . /etc/bashrc
fi
.
.
.
# User specific aliases and functions
alias ls='ls -hF --color=auto'
alias la='ls -ahF --color=auto'
# make the dir command work kinda like in windows (long format)
alias dir='ls --color=auto --format=long'
# make grep highlight results using color
alias grep='grep --color=auto'</pre>
<p>Aliases are a way to customize various commands on your system. They can make commands more convenient to use and reduce your keystrokes. Per-user aliases are often configured in the user’s <em>~/.bashrc</em> file.</p>
<p>If you find you are looking back through your command line history a lot, you may want to configure your history settings. Per-user history options can also be configured in <em>~/.bashrc</em>. For example, if you have a habit of using multiple terminals at once, you might want to enable the <em>histappend</em> option. Bash-specific shell options that are <a aria-label="undefined (opens in a new tab)" href="https://en.wikipedia.org/wiki/Boolean_data_type" target="_blank" rel="noreferrer noopener">boolean</a> in nature (take either <em>on</em> or <em>off</em> as a value) are typically enabled or disabled using the <em>shopt</em> built-in command. Bash settings that take a more complex value (for example, <em>HISTTIMEFORMAT</em>) tend to be configured by assigning the value to an environment variable. Customizing Bash with both shell options and environment variable is demonstrated below.</p>
<pre class="wp-block-preformatted"># Configure Bash History # Expand dir env vars on tab and set histappend
shopt -s direxpand histappend # - ignoreboth = ignorespace and ignoredup
HISTCONTROL='ignoreboth' # Controls the format of the time in output of `history`
HISTTIMEFORMAT="[%F %T] " # Infinite history
# NB: on newer bash, anything &lt; 0 is the supported way, but on CentOS/RHEL
# at least, only this works
HISTSIZE=
HISTFILESIZE= # or for those of us on newer Bash
HISTSIZE=-1
HISTFILESIZE=-1</pre>
<p>The <em>direxpand</em> option shown in the example above will cause Bash to replace directory names with the results of word expansion when performing filename completion. This will change the contents of the readline editing buffer, so what you typed is masked by what the completion expands it to.</p>
<p>The <em>HISTCONTROL</em> variable is used to enable or disable some filtering options for the command history. Duplicate lines, lines with leading blank spaces, or both can be filtered from the command history by configuring this setting. To quote Dusty Mabe, the engineer I got the tip from:</p>
<blockquote class="wp-block-quote">
<p><em>ignoredup</em> makes history not log duplicate entries (if you are running a command over and over). <em>ignorespace</em> ignores entries with a space in the front, which is useful if you are setting an environment variable with a secret or running a command with a secret that you don’t want logged to disk. <em>ignoreboth</em> does both.</p>
<p><cite>Dusty Mabe – Redhat Principle Software Engineer, June 19, 2020</cite></p></blockquote>
<p>For users who do a lot of work on the command line, Bash has the <em>CDPATH</em> environment variable. If <em>CDPATH</em> is configured with a list of directories to search, the <em>cd</em> command, when provided a relative path as its first argument, will check all the listed directories in order for a matching subdirectory and change to the first one found.</p>
<pre class="wp-block-preformatted"># .bash_profile # set CDPATH CDPATH="/var/home/username/favdir1:/var/home/username/favdir2:/var/home/username/favdir3" # or could look like this
CDPATH="/:~:/var:~/favdir1:~/favdir2:~/favdir3"</pre>
<p><em>CDPATH</em> should be updated the same way <em>PATH</em> is typically updated – by referencing itself on the right hand side of the assignment to preserve the previous values.</p>
<pre class="wp-block-preformatted"># .bash_profile # set CDPATH
CDPATH="/var/home/username/favdir1:/var/home/username/favdir2:/var/home/username/favdir3" # or could look like this
CDPATH="/:~:/var:~/favdir1:~/favdir2:~/favdir3" CDPATH="$CDPATH:~/favdir4:~/favdir5"
</pre>
<p><em>PATH</em> is another very important variable. It is the search path for commands on the system. Be aware that some applications require that their own directories be included in the <em>PATH</em> variable to function properly. As with <em>CDPATH</em>, appending new values to <em>PATH</em> can be done by referencing the old values on the right hand side of the assignment. If you want to prepend the new values instead, simply place the old values (<em>$PATH</em>) at the end of the list. Note that on Fedora, the list values are separated with the colon character (<strong>:</strong>).</p>
<pre class="wp-block-preformatted"># .bash_profile # Add PATH values to the PATH Environment Variable
PATH="$PATH:~/bin:~:/usr/bin:/bin:~/jdk-13.0.2:~/apache-maven-3.6.3" export PATH</pre>
<p>The command prompt is another popular candidate for customization. The command prompt has seven customizable parameters:</p>
<blockquote class="wp-block-quote">
<p><strong>PROMPT_COMMAND</strong> If set, the value is executed as a command prior to issuing each primary prompt ($PS1). </p>
<p><strong>PROMPT_DIRTRIM</strong> If set to a number greater than zero, the value is used as the number of trailing directory components to retain when expanding the \w and \W prompt string escapes. Characters removed are replaced with an ellipsis. </p>
<p><strong>PS0</strong> The value of this parameter is expanded like <em>PS1</em> and displayed by interactive shells after reading a command and before the command is executed. </p>
<p><strong>PS1</strong> The primary prompt string. The default value is ‘<strong>\s-\v\$</strong> ‘. …</p>
<p><strong>PS2</strong> The secondary prompt string. The default is ‘<strong><em>&gt;</em></strong> ‘. <em>PS2</em> is expanded in the same way as <em>PS1</em> before being displayed.</p>
<p><strong>PS3</strong> The value of this parameter is used as the prompt for the <em>select</em> command. If this variable is not set, the <em>select</em> command prompts with ‘<strong>#?</strong> ‘</p>
<p><strong>PS4</strong> The value of this parameter is expanded like <em>PS1</em> and the expanded value is the prompt printed before the command line is echoed when the <em>-x</em> option is set. The first character of the expanded value is replicated multiple times, as necessary, to indicate multiple levels of indirection. The default is ‘<strong><em>+</em></strong> ‘.</p>
<p><cite>Reference Documentation for Bash<br />Edition 5.0, for Bash Version 5.0.<br />May 2019</cite></p></blockquote>
<p>An entire article could be devoted to this one aspect of Bash. There are copious quantities of information and examples available. Some example dotfiles, including prompt reconfiguration, are provided in a repository linked at the end of this article. Feel free to use and experiment with the examples provided in the repository.</p>
<h2>Conclusion</h2>
<p>Now that you are armed with a little knowledge about how Bash works, feel free to modify your Bash dotfiles to suit your own needs and preferences. Pretty up your prompt. Go nuts making aliases. Or otherwise make your computer truly yours. Examine the content of <em>/etc/profile</em>, <em>/etc/bashrc</em>, and <em>/etc/profile.d/</em> for inspiration.</p>
<p>Some comments about terminal emulators are fitting here. There are ways to setup your favorite terminal to behave exactly as you want. You may have already realized this, but often this modification is done with a … wait for it … dotfile in the users home directory. The terminal emulator can also be started as a login session, and some people always use login sessions. How you use your terminal, and your computer, will have a bearing on how you modify (or not) your dotfiles.</p>
<p>If you’re curious about what type session you are in at the command line the following script can help you determine that.</p>
<pre class="wp-block-preformatted">#!/bin/bash case "$-" in (*i*) echo This shell is interactive ;; (*) echo This shell is not interactive ;;
esac</pre>
<p>Place the above in a file, mark it executable, and run it to see what type of shell you are in. <em>$-</em> is a variable in Bash that contains the letter <strong>i</strong> when the shell is interactive. Alternatively, you could just echo the $- variable and inspect the output for the presence of the <strong>i</strong> flag:</p>
<pre class="wp-block-preformatted">$ echo $-</pre>
<h2>Reference information</h2>
<p>The below references can be consulted for more information and examples. The Bash man page is also a great source of information. Note that your local man page is guaranteed to document the features of the version of Bash you are running whereas information found online can sometimes be either too old (outdated) or too new (not yet available on your system).</p>
<p><a href="https://opensource.com/tags/command-line">https://opensource.com/tags/command-line</a></p>
<p><a href="https://opensource.com/downloads/bash-cheat-sheet">https://opensource.com/downloads/bash-cheat-sheet</a></p>
<p>You will have to enter a valid email address at the above site, or sign up, to download from it.</p>
<p><a href="https://opensource.com/article/19/12/bash-script-template">https://opensource.com/article/19/12/bash-script-template</a></p>
<p>Community members who provided contributions to this article in the form of example dotfiles, tips, and other script files:</p>
<ul>
<li>Micah Abbott – Principal Quality Engineer</li>
<li>John Lebon – Principal Software Engineer</li>
<li>Dusty Mabe – Principal Software Engineer</li>
<li>Colin Walters – Senior Principal Software Engineer</li>
</ul>
<p>A repository of example dotfiles and scripts can be found here:</p>
<p><a href="https://github.com/TheOneandOnlyJakfrost/bash-article-repo">https://github.com/TheOneandOnlyJakfrost/bash-article-repo</a></p>
<p>Please carefully review the information provided in the above repository. Some of it may be outdated. There are many examples of not only dotfiles for Bash, but also custom scripts and pet container setups for development. I recommend starting with John Lebon’s dotfiles. They are some of the most detailed I have seen and contain very good descriptions throughout. Enjoy!</p>
</div>


https://www.sickgaming.net/blog/2020/07/...zing-bash/
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

Forum software by © MyBB Theme © iAndrew 2016