Skip to content

Latest commit

 

History

History
2345 lines (1751 loc) · 122 KB

readme.rst

File metadata and controls

2345 lines (1751 loc) · 122 KB

USRHOME -- Easily Clonable Unix Shell Configuration & Tools

License Version https://img.shields.io/badge/Supports-macOS,_Kali_Linux,_zsh_as_main_or_subshell-green https://img.shields.io/badge/Supports-macOS,_Kali_Linux,_Ubuntu_Linux,_Rocky_Linux_Bash_as_main_or_subshell-green https://img.shields.io/badge/Installer_tested_on-macOS,_Kali_zsh-green https://img.shields.io/badge/Installer_tested_on-Ubuntu_Linux,_Rocky_Linux_Bash-green
Author:Pierre Rouleau
Copyright:© 2024, Pierre Rouleau

Introduction

USRHOME is Unix shell configuration project that provides a set of shell script tools. It provides tools to instrument shells: specialize shells to add support for various tools, while leaving the main login shell intact if needed.

With USRHOME you can instrument multiple shells independently. Once the rules are set (in terms of sourced scripts) you can quickly open a shell and activate support for the tools you need just for that shell. You can for instance have a shell that supports Rust development, another that adds gcc-based C++ compiler on macOS while keeping the Clang as default for its normal shell. Each shell can have its own, independent PATH easily set by the script that controls the shell environment. You retain the standard shell untouched unless you want to activate some of these environments inside it.

USRHOME support:

  • macOS and multiple Linux distributions.
  • The Z Shell and Bash shell.
  • Multiple computers:
    • the configuration infrastructure logic is held inside this USRHOME Git repository,
    • the user-specific configuration logic for several computers or VMs is stored inside a sibling, private, repository; the usrcfg (and USRHOME provides template files for it).

With USRHOME, all user shell configuration dot files (such as your ~/.bashrc) are turned into symbolic links to USRHOME dot files, allowing shell configuration logic to be under VCS control.

USRHOME repository files provides the basic shell configuration infrastructure logic. It uses your own personal/private configuration logic stored into your files located inside your usrcfg repository.

  • That can be used inside all the computers you use; the usrcfg files can select logic based on host names or other criteria. The goal is to be able to store all shell configuration logic into two VCS repositories: the public one (USRHOME) and your private one.

At the moment USRHOME supports:

  • A basic configuration of zsh and Bash for macOS and several Linux distributions.
    • It works when Bash or zsh is used as the default shell for login and non-login shells.
    • It supports the latest versions of macOS where zsh is the default shell (since macOS 10.15 Catalina), and older versions of macOS where an old version of Bash is the default shell.
    • It also supports several Linux distributions where Bash is the default shell and some where zsh is the default shell.

USRHOME provides several defined prompt configurations with ability to control the terminal title bar. It comes with a default but you can select the prompt model for the Bash and Z shell independently. The intent of these prompts is not to provide colourful configurations with fancy fonts and emoji but just provide a basic environment that will work over several versions of Operating Systems and will support both shells in several terminal emulator programs.

These are:

  • the default macOS Terminal.app,
  • the default Linux terminal applications,
  • inside Emacs various terminal shell modes.

USRHOME is also designed to work well when used with Emacs using my Pragmatic Emacs Library which provides extensive key bindings for use in these Operating systems and allow extended use of the numeric keypad. USRHOME logic is Emacs aware and uses the INSIDE_EMACS environment variable to control the behaviour of some features when they are invoked inside a shell running inside Emacs.

USRHOME makes one important assumption about the organization of the directories in your file system: it specifically assumes that:

  • The directory that holds the USRHOME directory tree also holds a directory tree called usrcfg that holds the user-specific and private configuration information.

It is recommended to create a directory that only holds the USRHOME and your usrcfg repositories; this will help you perform search restricted to the content of the files stored inside these only.

The sections titled The zsh Configuration Files and The User Configuration Files used by USRHOME describe the files used.

On shell startup, USRHOME takes over and sets the value of several environment variables that identify the location of directories and USRHOME state.

To help you create your usrcfg repository, USRHOME provides a set of usrcfg template files that correspond to what I use in my usrcfg repository. This also corresponds to what is shown in the diagram included in the section titled The Z and Bash Shell Startup, Dot Files and User Configuration.

Quick Overview Example

Here's two screen captures of USRHOME taken on macOS Sonoma and Rocky Linux 9.3.

macOS shells

The macOS Sonoma default shell is zsh. I have installed the latest Bash shell via Homebrew and also installed Rust. These are available on the default zsh shell, which is shown starting in the first terminal seen in the back (ttys013). The PATH available in that shell has 17 entries. It has access to Rust and several Homebrew directories.

I have also configured Terminal to start a Bash login shell. That shell (ttys014) is also controlled by USRHOME but my USRHOME setting prevents USRHOME to add anything on the PATH of the login shells. They have 10 directories in their PATH; the first one being /usr/local/bin.

Then I start another terminal (ttys015) with macOS default zsh non-login interactive shell. As for the first one (ttys013), it sets up Homebrew and Rust because my USRHOME setup is done that way for those shells. It has 17 directories in PATH. Then I create a Bash sub-shell. You can see it in the prompt. The L2 is the value of the SHLVL variable identifying the shell nested level. From bash I create a zsh sub-shell from where I launch a sleep 100 command in the background. The zsh shows 1 ⚙ identifying a running background job. And when I issue an invalid command, it prints the exit code (127) followed by a red ⨯.

res/macOS-shells.png

Rocky Linux 9.3 shells

The screen shot show a setting I have for Rocky Linux 9.3. Rocky Linux 9.3 default shell is Bash 5.1. Again here I started two terminal instances: the first one launches the default Bash, instrumented with the exact same USRHOME settings than my macOS one. On Linux, Homebrew is not used. But it also activates Rust.

USRHOME does some check for vulnerabilities and it detects a possible one in Rocky Linux 9.3 and reports it when it is executing as the first level. The prompt prints:

  • the exit code of the last command,
  • the elapsed time (duration) of the completed command,
  • the shell nested level,
  • the number of background jobs running,
  • the user name @ hostname @ current time in 24-hour format
  • the current directory in side square brackets.

The second non-login shell is executing a terminal-based Emacs process, which runs a terminal mode shell. The USRHOME shell is Emacs-aware. The bash prompt is not affected when running inside Emacs. It can display the same information. You can see the PATH components shown by the showpath command.

USRHOME will sanitize and report sloppy PATH such as PATH with duplicate entries and empty entries. Here everything is fine.

When the shell is placed in sudo mode, the prompt changes color and shows a # instead of a $ after the word bash.

The third terminal is configured to launch Bash in login mode. Here, USRHOME does not add anything to the PATH; the Bash login shells are unmodified and do not have access for any extra tools, therefore the PATH is shorter. These shells do not perform USRHOME simple (and quite limited) vulnerability check.

Also note that, to help distinguish the login shell, I set the login shell prompt to red and the color of the non-login prompt to blue.

res/RockyLinux-shells.png

Kali Linux zsh shells with tracing enable

You can activate shell tracing with USRHOME. When enabled, the shell prints what file is sourced when the shell starts, as this is shown in the Kali Linux, where zsh is the default shell.

Rust is not installed in that system but it uses the same USRHOME common configuration as the others (with the temporary exception of enabling tracing) and the shell prints a warning.

res/Kali-Linux-zshell.png

It would be possible to move the request to use Rust from the common configuration file (in this case the file usrcfg/do-user.sh, that has logic similar to the example template file for do-user.sh ) into a node-specific file that the usrcfg logic could identify. That could be done by the do-user.sh in the way that the usrcfg do-user-zshrc.sh example file does.

If you want to know how this all works, read on (and see the section titled The Z Shell Startup, Dot Files and User Configuration).

How to Set it Up

  • Open the default Bash or Z Shell.

  • Create a directory that will hold 2 sub-directories: usrhome (the USRHOME repo directory tree) and usrcfg (your own repository that will hold your configuration for your computer(s). I use ~/my/shell for that.

  • Change the current directory to the directory you just created (for example cd ~/my/shell ).

  • Clone the USRHOME repository by doing: git clone https://github.com/pierre-rouleau/usrhome.git

  • Change the current directory to the root of your USRHOME repository: cd usrhome

  • Execute the setup script from the root directory of the USRHOME depot. This way the script can identify the location of your usrhome directory and create a usrcfg with some basic files can can later update to suit your needs. So, do this from the directory like ~/my/shell you selected before:

    cd usrhome
    setup/setup-usrhome
    
    • It will print what will be done and prompt before proceeding:
      • Create a usrcfg directory inside the same directory that holds the usrhome directory.
      • Create all required and optional user-specific configuration files, using the corresponding templates as basis.
      • Finally create symbolic link in your home directory to point to the Z Shell and Bash configuration files stored inside the usrhome/dot directory. Before proceeding it will create backup of files that are already present.

Once that's done you should be able to open a Z Shell with the zsh command and see the basic prompt supported by the project and have access to the commands documented below.

The next step will to migrate any Z Shell startup logic you might have had in your old files that have been backed up by the startup script. USRHOME expects that extra user-specific logic to be stored inside files located inside the usrcfg directory.

For that you need to understand which file is sourced when the Z Shell is started in the various ways it is started. Read the section titled The Z Shell Startup, Dot Files and User Configuration.

Then you can decide to use your original ~/.zshrc and other Z Shell configuration files that have been backed-up by setup/setup-usrhome and copy all or part of their content inside the corresponding files inside the usrcfg directory.

You can also take a look at the other example files located in the usrhome/template directory and use ideas from there.

USRHOME Organization

The Bash Configuration Files

The Bash shell uses the configuration files listed in the left column (which includes the ~/.profile file also uses by sh). USRHOME replaces them to symbolic link files that point to the USRHOME files listed in the right column.

Location of Symbolic Link Location of the USRHOME files pointed by the symlinks
~/.profile $USRHOME_DIR/dot/profile.sh
~/.bash_profile $USRHOME_DIR/dot/bash_profile.bash
~/.bash_login $USRHOME_DIR/dot/bash_login.bash
~/.bashrc $USRHOME_DIR/dot/bashrc.bash
~/.bash_logout $USRHOME_DIR/dot/bash_logout.bash

The zsh Configuration Files

The Z Shell uses the configuration files listed in the left column. USRHOME replaces them to symbolic link files that point to the USRHOME files listed in the right column.

Location of Symbolic Link Location of the USRHOME files pointed by the symlinks
~/.zshenv $USRHOME_DIR/dot/zshenv.zsh
~/.zprofile $USRHOME_DIR/dot/zprofile.zsh
~/.zshrc $USRHOME_DIR/dot/zshrc.zsh
~/.zlogin $USRHOME_DIR/dot/zlogin.zsh
~/.zlogout $USRHOME_DIR/dot/zlogout.zsh

USRHOME Internal Configuration Files

As shown by the diagram in the section titled The Z and Bash Shell Startup, Dot Files and User Configuration, USRHOME uses several other configuration files that are sourced when the shell starts. Some are used by the Bash shell, some by the Z Shell some by both. All of these files are source and stored in USRHOME ibin directory.

The following files are not meant to be used manually. They are executed when the shell starts.

$USRHOME/ibin File Purpose
setfor-alias

Defines USRHOME alias and shell functions that are common to Bash and the Z Shell. The file defines several command aliases, including the USRHOME-specific command aliases that use the following ibin/setfor- files:

  • $USRHOME_DIR/ibin/setfor-prompt-model-to: sourced to implement setfor-prompt-model-to
  • $USRHOME_DIR/ibin/setfor-prompt-toggle-usr-host: sourced to implement setfor-prompt-toggle-usr-host
  • $USRHOME_DIR/ibin/setfor-shell-toggle-tracing: sourced to implement setfor-shell-toggle-tracing
setfor-bash-alias Defines USRHOME alias and shell functions that are only used in the Bash shell.
setfor-path

Holds the USRHOME logic that controls modification of the PATH environment variable and functions that deals with it. Also defines and runs functions that perform a simple security check that verifies for the presence of some known compromised libraries in the system, printing a warning if they are found.

It sources the following extra ibin files:

  • USRHOME_DIR/ibin/envfor-homebrew, when USRHOME_USE_HOMEBREW environment variable is set to 1 in the file usrcfg/setfor-all-config.sh. That prepends the Homebrew directory to the path.
  • USRHOME_DIR/ibin/envfor_usrhome, always, to prepend the USRHOME_DIR/bin to PATH and ~/bin if present.
setfor-zsh-alias Defines USRHOME alias and shell functions that are only used in the Z Shell.
shell-tracing.sh Defines the usrhome_trace_in() and usrhome_trace_out() shell functions USRHOME executes to print a trace of which configuration file is used when the shell starts when the user activates shell tracing by the $USRHOME_TRACE_SHELL_CONFIG environment variable to 1 inside the file usrcfg/setfor_shell_tracing.sh.

Sourced Files Implementing USRHOME Provided Commands

USRHOME provides several commands that use shell sourced files, also stored in the USRHOME/ibin directory. There are 3 groups of such files:

Shell Environment Control Commands:

The files used by the use-ENV commands. These commands setup the current shell to use a specific set of commands or tools. USRHOME provides some of these commands:

$USRHOME/ibin File Purpose
envfor-cbr Implements the use-cbr command.
envfor-diff Implements the use-diff command that sets up how USRHOME diff operates in the current shell.
envfor-emacs-for-man Implements the use-emacs-for-man command.
envfor-pel Implements the pel command.

The user would probably want to create some extra ones; the usrhome/template/usrcfg/ibin directory provides some examples.

Simple Commands that affect the current shell:

$USRHOME/ibin File Purpose
do-cbr Implements the cbr command.
do-cd-to Implements the cd-to command.
do-clrenv Implements the clrenv command.
do-sanitize-path.sh Implements the sanitize-path command for Bash and sh.
do-sanitize-path.zsh Implements the sanitize-path command for zsh.
do-setenv Implements the setenv command.
do-usrcfg Implements the usrcfg command.
do-usrhome Implements the usrhome command.

Helper Sourced Files

$USRHOME/ibin File Purpose
which-shell

Identifies the shell (Bash, Z Shell, or other): sets the USRHOME_SHELL environment variable to "zsh", "bash", etc.

It is used by other USRHOME shell functions. Can also be used by user's shell functions.

The User Configuration Files used by USRHOME

File Name (link to template) Description
usrcfg/setfor-all-config.sh

Required. Holds user configuration that applies to the Bash and Z Shell. Therefore it must be written in POSIX sh script, compatible with both Bash and Z Shell.

It defines:

  • USRHOME_TRACE_SHELL_CONFIG which controls shell tracing:
    • 0 : disable shell tracing,
    • 1 : enable shell tracing to shell stdout,
    • file name: enable shell tracing to shell stdout and to the specified file. The file name must be an absolute file name inside an existing directory.
  • USRHOME_USE_HOMEBREW:
    • 0: don't use Homebrew,
    • 1: to activate the use of (already installed) Homebrew.
  • The USRHOME concept directory variables (see next section) which includes: USRHOME_DIR_MY, USRHOME_DIR_LIC, USRHOME_DIR_LOG, USRHOME_DIR_DV, USRHOME_DIR_PRIV, USRHOME_DIR_PUB, USRHOME_DIR_TMP.
  • USRHOME_PROMPT_MODEL which select the prompt model. As described further in the USRHOME Prompt section, the following values are supported:
    • 0: prompt is not defined by USRHOME logic, user code should define it or use system's default.
    • 1,2 or 3: USRHOME pre-defined prompt.
  • USRHOME_CONFIG_AT_LOGIN:
    • Leave undefined, if you do not want to modify PATH in a login shell.
    • 1: define it to 1 if you want the PATH modified in the login shell so it has the same configuration than then non-login interactive shell.

The file also sources the usrhome/ibin/shell-tracing.sh to define USRHOME-specific logic to control optional shell config file tracing.

usrcfg/do-user-zprofile.zsh

Optional. User-specific Z Shell zprofile logic.

  • This must be written in Z Shell compatible logic.
  • It also holds some USRHOME-specific logic to control optional shell config file tracing.
usrcfg/do-user-zshrc.zsh

Required for Z Shell. User-specific Z Shell specific configuration.

  • This must be written in Z Shell compatible logic.
  • It also holds some USRHOME-specific logic to control optional shell config file tracing.
  • That file could also source a node-specific file stored inside the usrcfg/node/do-NODE-zshrc.zsh file where NODE is identified with hostname -s.
usrcfg/do-user-bash_profile.bash

Optional. User-specific Bash Shell specific configuration. In some system the ~/.bash_login is executed during login. On those systems it might be useful to write configuration logic that must only be executed once, at login, inside this file, as one would do with the ~/.bash_login.

  • This must be written in Bash compatible logic.
  • It should also hold some USRHOME-specific logic to control optional shell config file tracing.
  • That file could also source a node-specific file stored inside the usrcfg/node/do-NODE-bash_profile.bash file where NODE is identified with hostname -s.
usrcfg/do-user-bashrc.bash

Required for Bash. User-specific Bash Shell specific configuration.

  • This must be written in Bash compatible logic.
  • It also holds some USRHOME-specific logic to control optional shell config file tracing.
  • That file could also source a node-specific file stored inside the usrcfg/node/do-NODE-bashrc.bash file where NODE is identified with hostname -s.

As said above, the usrcfg directory is expected to be a sibling to the usrhome directory; they must both be inside the same parent directory. This allows USRHOME to automatically set the USRHOME_DIR_USRCFG environment variable to hold the full path of the usrcfg directory. It's recommended to place the USRHOME directory and the usrcfg directory inside a parent directory that only holds these two directories. That simplifies your searches when you need to identify where some logic is placed.

See the section titled The Z Shell Startup, Dot Files and User Configuration for more information.

The USRHOME Configuration Environment Variables

Conventions:

  • All environment variables used by USRHOME have a name that starts with USRHOME_.
  • All of those that identify the path of a directory have a name that starts with USRHOME_DIR_.
  • All internal USRHOME environment variables have a name that start with USRHOME__. These variables are only used by USRHOME logic and should not be modified by user's logic.
Environment Variable Name Purpose
USRHOME_TRACE_SHELL_CONFIG Set to 1 to activate tracing of the configuration file sourcing. Use the usrhome-shell-toggle-tracing command to toggle this in the current shell.
USRHOME_PROMPT_SHOW_USR_HOST Set to 1 to display user name and host name in the prompt. Use the usrhome-prompt-toggle-usr-host command to toggle this in the current shell.
USRHOME_CONFIG_AT_LOGIN Set to 1 to inform USRHOME files to perform configuration when invoked in a login shell. If you want to restrict use of USRHOME controlled configuration to interactive shells, don't set it, or set it to 0. If set this must be set inside the usrcfg/setfor-all-config.sh file.
USRHOME_USE_HOMEBREW Set to 1 when using Homebrew, to add Homebrew directories to the PATH.
USRHOME_DIR Path to the usrhome directory. The setup/setup-usrhome installation script appends code to set the value of that environment variable.
USRHOME_DIR_HELPDIR Optional environment variable. If defined it identifies the directory where Zsh Builtin Help files are located. Define it only when the default USRHOME logic in usrhome/dot/zshrc.zsh is not able to identify that directory for your system and therefore the help command is not able to operate like it would under Bash.
USRHOME_PROMPT_MODEL

Optional environment variable. Identifies the syntax of the prompt used by the shell. The prompts for zsh and Bash are independent and you can define a different prompt model value for each. The supported values are:

  • 0 : no prompt defined by USRHOME. Either use the shell default or a user specified prompt inside the shell specific usrcfg file. default prompt.
  • 1 (or not defined), 2 or 3, a USRHOME pre-defined shell prompt.

Users can change the prompt dynamically by issuing a usrhome-prompt-model-to NUMBER command.

Caution!! Under zsh it might be necessary to execute exec zsh to update the prompt. This depends on how the prompt is implemented.

  • You can identify a prompt number that would require restarting zsh in the environment variable USRHOME_PROMPT_MODEL_REQUIRES_RESTART.
  • The command will check if the zsh has any running job and will proceed only if there are none.
USRHOME_ORIGINAL_PATH Set to the value of PATH before USRHOME adds to it. You can restore that value with the usrhome-switch-path command if necessary for testing purposes.
USRHOME_SHOW_PATH_ACTIVATION Set to 1 to see PATH changes done by the various use-ENV commands, including their use when the shell starts.

When USRHOME Z Shell startup logic executes, USRHOME sets these other environment variables:

Environment Variable Name Purpose
USRHOME_DIR_MY Main user directory, used by USRHOME Directory Navigation. Change current directory to this directory with the cdh command.
USRHOME_DIR_LIC Directory where you can keep the software license files for the software tools you use. Change current directory to this directory with the cdlic command.
USRHOME_DIR_LOG Directory where your own log files and notes can be stored. Change current directory to this directory with the cdlog command.
USRHOME_DIR_DV Development directory, used by USRHOME Directory Navigation. Change current directory to this directory with the cddv command.
USRHOME_DIR_PRIV Private development directory, used by USRHOME Directory Navigation. Change current directory to this directory with the cdpriv command.
USRHOME_DIR_PUB Public development directory, used by USRHOME Directory Navigation. Change current directory to this directory with the cdpub command.
USRHOME_DIR_TMP User local temporary directory. Change current directory to this directory with the cdtmp command.
USRHOME_DIR_USRCFG The path of the user configuration directory. Something like /Users/roup/my/dv/usrcfg. Use the usrcfg command to change the current directory to that directory.
USRHOME__IN_LOGIN USRHOME Internal environment variable: A logic flag set to 1 by usrhome/dot/zprofile.zsh and usrhome/dot/bash_profile.bash to inform the shell code that the sourcing of the configuration files is being done by a login shell. When the sourcing of the configuration file is done by a sub-shell this is not set. The usrcfg/setfor-all-config.sh file can set the USRHOME_CONFIG_AT_LOGIN flag to 1 to indicate the USRHOME configuration should be done at login.
USRHOME__PATH_SET USRHOME Internal environment variable: A logic flag set when USRHOME modified PATH.
USRHOME__USRCFG_SEEN USRHOME Internal environment variable: A logic flag set when USRHOME has processed user-specified usrcfg configuration.

More information about these in the section Cd to Conceptual Directories.

USRHOME Commands and Scripts

Shell Behavior Control

USRHOME Command Name Description
usrhome-shell-toggle-tracing

Toggle tracing the execution of the shell configuration files when a shell starts. This toggles the value of the USRHOME_TRACE_SHELL_CONFIG environment variable from 0 to 1 and vice-versa.

Note that if the variable value was a file name, toggling it twice will simply re-activate the tracing to stdout, not to the file.

  • The original value of this environment variable is set inside your ``usrcfg/setfor-all-config.sh file. The default value is 0 as identified by usrhome/template/setfor-all-config.sh used to initialize the usrcfg file.

Caution this command perform an exec command for the current shell, which will wipe history. The command check if there a re any running jobs and will not proceed if there are any.

usrhome-prompt-toggle-usr-host

Toggle the inclusion of the user name and host name inside the prompt.

Caution!! Under zsh it might be necessary to execute exec zsh to update the prompt. This depends on how the prompt is implemented.

  • You can identify a prompt number that would require restarting zsh in the environment variable USRHOME_PROMPT_MODEL_REQUIRES_RESTART.
  • The command will check if the zsh has any running job and will proceed only if there are none.

The command is not affected by this limitation when issued in the Bash shell.

usrhome-prompt-model-to NUMBER

Dynamically change the prompt model to the specified NUMBER.

  • This command also supports the -h and --help command line options which pint the usage.

Caution!! Under zsh it might be necessary to execute exec zsh to update the prompt. This depends on how the prompt is implemented.

  • You can identify a prompt number that would require restarting zsh in the environment variable USRHOME_PROMPT_MODEL_REQUIRES_RESTART.
  • The command will check if the zsh has any running job and will proceed only if there are none.

The command is not affected by this limitation when issued in the Bash shell.

Note that the above commands will not execute if there are any running sub-process jobs under the shell. That's because these commands execute exec zsh and that wipes out shell knowledge about these background jobs, making it difficult to bring them back into the foreground.

Shell Status Info

USRHOME provides the following special commands that provide useful information about the current shell and can also serve as help reminders when writing shells script code.

These are implemented as shell functions or alias inside usrhome/ibin/setfor-alias.

USRHOME Command Name Description
info-desktop

Print the name of the desktop software type being used. Internally also set the shell variable USRHOME_DESKTOP which can later be used inside shell scripts.

info-prompt [-q]

Print information about shell's prompt controlling variables. By default it prints the values of all variables. With the -q option it only prints the values of the USRHOME_PROMPT_MODEL and USRHOME_PROMPT_MODEL_OVERRIDE values. The first one shows the value of the default prompt mode, the second one, if set, is the model of the current prompt, overriding the default.

info-rosetta2

Available on macOS only. Checks whether Rosetta 2 is installed and prints info about it.

info-shell-special-var [ARGS]

List the shell special variables like $*, $@, $? and others, describing their purpose and showing their values.

  • When command line arguments are passed to the command, it prints the positional arguments, the value of "$*" and "$@" helping you remember the basic differences. Try it by passing a glob to it like *.
  • Implemented in: usrhome/ibin/setfor-alias as a shell function.
info-shell

Show current and default shell environment variable names and values.

Terminal Window Control

USRHOME Command Name Description
set-title [TITLE] Set the terminal's title to the value passed as its first parameter. The terminal title is shown on the window title bar. The command accepts only 1 parameter, so if you want to set the title with embedded spaces just quote the entire title. With no argument: removes the title.
restore-title Restore title that might have been affected by error.

Directory Navigation

Extensions to the cd command.

USRHOME Command Name Description
.. [DIR] Perform cd ../DIR. If DIR is not specified, performs cd ..
... [DIR] Performs cd ../../DIR If DIR is not specified, performs cd ../..
.... [DIR] Performs cd ../../../DIR If DIR is not specified, performs cd ../../..
cd-to Search for file specified by file FNAME or directory DNAME in current directory tree.
  • cd-to [-h|--help]
 
  • cd-to [-H] FNAME
 
  • cd-to -d [-H] DNAME
  • The FNAME and DNAME can be expressed with fd glob support.
  • By default, does not search into hidden directories. Specify the -H option to search into them.
  • If one file/directory is found, change the current directory to the directory that holds it and print the ls -l for it.
  • If several files/directories are found, print a cautionary note with the number of found items and their path names (relative to current directory).
    • If the EDITOR environment variable is set, the script prompts the user for editing the items. On a 'y' answer it edits the files found using the editor selected by EDITOR.
  • File search performed by the fd utility. If it's not installed the command exits with an error.
  • Exit code:
    • 0: one file was found, the current directory was changed.
    • 1: no file found.
    • n: the number of files found if they were not edited.
pel [SUBDIR] Change current directory to PEL depot directory or its SUBDIR if specified. Also set terminal title to 'PEL'.
usrhome [SUBDIR] Change current directory to USRHOME depot directory or its SUBDIR if specified. Also set terminal title to 'USRHOME'.
usrcfg [SUBDIR] Change current directory to the USRHOME personal/persistent configuration directory, usrcfg or its SUBDIR if specified. Also set terminal title to 'USRHOME:usrcfg'

Cd to Conceptual Directories

USRHOME Command Name Description
cdh [SUBDIR] cd to home: the directory identified by USRHOME_DIR_MY or its identified SUBDIR.
cdlic [SUBDIR] cd to the directory identified by the USRHOME_DIR_LIC or its identified SUBDIR.
cdlog [SUBDIR] cd to the directory identified by the USRHOME_DIR_LOG or its identified SUBDIR.
cdv [SUBDIR] On macOS only, cd to the /Volume directory or its identified SUBDIR.
cddv [SUBDIR] cd to main development; the directory identified by USRHOME_DIR_DV or its identified SUBDIR.
cdpriv [SUBDIR] cd to private projects; the directory identified by USRHOME_DIR_PRIV or its identified SUBDIR.
cdpub [SUBDIR] cd to public projects; the directory identified by USRHOME_DIR_PUB or its identified SUBDIR.
cdtmp [SUBDIR] cd to user-specific temporary directory, identified by USRHOME_DIR_TMP or its identified SUBDIR.

The commands described above change the current directory to several conceptually important (holder) directories. Those directories are identified by USRHOME environment variables. The name of these environment variables start with the USRHOME_DIR_ prefix. They are:

USRHOME_DIR_MY:

The directory where all your development directories are located.

  • On macOS, it is often different from HOME:
    • it could be $HOME/Documents if you want the files located in that directory tree replicated by Apple iCloud or,
    • it could be another directory, like $HOME/my if you do not want them replicated and stored in the iCloud.
  • On any system, it could be used to identify a directory tree specific to a given activity or content type or just be set to the value of $HOME.
USRHOME_DIR_LIC:
The directory where you could collect all the licence files you have agreed with when using a software service or package.
USRHOME_DIR_LOG :
The directory where you could store activity log files and notes.
USRHOME_DIR_DV:
The directory where you store your main, or most-active, development sub-directories. For example on my systems I often have a ~/code or ~/my/code or ~/my/dv directory where I place my most active projects (or symlinks to these directories). This can be located anywhere.
USRHOME_DIR_PRIV:
The directory where you store your private development sub-directories. That could be something you do not want to publish because it's not ready, or it could be the directories for your various contract work. This can be located anywhere.
USRHOME_DIR_PUB:
The directory where you store your secondary, public, sub-directories. That could hold a set of repositories that are forks of other projects to which you contribute, or libraries and tools you want to build yourself, anything you do not consider your main or most-active development. This can be located anywhere.
USRHOME_DIR_TMP:
The name of a directory where your user's temporary files may be stored, in a separate directory than the standard /tmp directory. That can be used for testing code and checking if your tested code suffers from temporary file leakage.

Where to Define these Environment Variables

These environment variables are defined in the user persistent configuration file common to Bash and Z Shell: the usrcfg/setfor-all-config.sh file.

During installation, the setup/setup-usrhome script initializes them to the value stored in usrhome/template/setfor-all-config.sh template file. You can change them or add logic in your file to control their values any way you need.

The following commands are shortcuts to change the current directory to one of these directories.

Listing Files/Directories/Links

The following command shortcuts for specialized use of ls are provided by USRHOME.

USRHOME Command Name Description
l

Colorized ls that also shows the file type symbol.

  • Supports supplementation ls options and arguments.
la

Same as l but also show hidden files.

  • Supports supplementation ls options and arguments.
ll

ls -l with colorized and file type symbols.

  • Supports supplementation ls options and arguments.
lla

Same as ll but also show hidden files.

  • Supports supplementation ls options and arguments.
lt

ls -ltr with colorized and file type symbols.

  • Supports supplementation ls options and arguments.
lta

Same as lt but also show hidden files.

  • Supports any ls options.
lsd [NAME]

List sub-directories in current directory.

  • NAME: optional name or first letters of the names.
lsda [NAME]

List sub-directories in current directory, includes hidden directories.

  • NAME: optional name or first letters of the names.
lsl [-l] ['NAME']

List symbolic links in current directory.

  • With -l, list using the ls -l format.
  • NAME: optional symlink name glob pattern. Must be placed withing single quotes.
  • Also support the -h and --help options to show its usage.

Command to Display and Manipulate Environment Variables

The following commands help manage and read the content of environment variables.

USRHOME Command Name Description
clrenv VARNAME

Clear (remove) the environment variable specified by name from the environment of the current shell.

setenv VARNAME VALUE

Set the environment variable named VARNAME to the specified VALUE and inject it inside the current shell.

use-usrhome

Add USRHOME binary directory and ~/bin to PATH if present. This command is automatically executed for zsh shell started under USRHOME control.

use-homebrew

Add Homebrew directories to PATH if required for the CPU architecture. This command is automatically executed for zsh shell started under USRHOME control when the USRHOME_USE_HOMEBREW environment variable is set to 1 inside the USRHOME user's common shell configuration file usrcfg/setfor-all-config.sh .

use-info

Add info directories located in standard places to the INFOPATH environment variable. Use it to extend the INFOPATH when using the stand-alone GNU info reader or info within Emacs. It searches for info directories once per process tree inside the following potential locations:

  • Homebrew
  • Emacs source repository, which must be identified by the USRHOME_DIR_EMACS_SRC environment variable.

Currently this list of locations is hard coded inside the usrhome/ibin/envfor-info file.

showpath [-n] [varname][PATH]

Print the value of PATH, MANPATH or LIBPATH, or any PATH specific environment variable placing each directory in its own line.

The command accepts shortcut names for MANPATH and LIBPATH as MAN and LIB respectively.

The command also accepts the name of any other environment variable that exists in the environment.

With the optional -n: print a left justified number on each line. Examples:

  • showpath : prints PATH, one directory per line,
  • showpath PATH: prints PATH, one directory per line,
  • showpath -n: prints PATH with numbered lines,
  • showpath -n PATH: prints PATH with numbered lines,
  • showpath -n MANPATH: prints MANPATH with numbered lines,
  • showpath MAN: prints MANPATH without numbers.

If the format of the path variable is incorrect, the command prints an error message on stderr. The errors detected include a leading or trailing separator or multiple consecutive separators. The exit code are:

  • 0 on success (or help),
  • 1 on invalid argument(s),
  • 2 when specified environment variable is not defined,
  • 3 when the format of the specified path is incorrect.

Note: when MANPATH is undefined, showpath uses the manpath command (if available) and prints the path it returns. It also prints a warning on stderr and exit with an exit-code of 0.

Help is printed when the -h or --help option is used.

usrhome-env Display the values of all USRHOME environment variables currently set in the shell.
usrhome-switch-path Modify PATH. Swap current PATH with the value stored inside the USRHOME_ORIGINAL_PATH environment variable. This is set to PATH value the system had inside the shell before USRHOME added support for itself and other tools.
sanitize-path

Check the PATH value of the current shell and sanitizes it:

  • removes duplicate entries.
  • removes empty entries,
  • print a warning when it modifies PATH.

Dynamic Path Management

The USRHOME commands and environment variables allow the dynamic management of the PATH in the current shell. Here's a screen shot of this being done on a macOS Computer running on Apple Silicon CPU architecture.

res/dynamic-path-management.png

Help for Zsh Builtin Commands

The Z shell does not support a help command that provides information on the shell builtin commands like Bash does. The Z Shell provides the run-help command instead but that is not always available. For instance, under macOS, it is aliased to man, which causes help requests to open the generic man page on zsh; something not very useful. On some Linux distributions, like Kali Linux, run-help is a shell function and will display the requested builtin help.

USRHOME implements the help command for zsh as an alias to run-help. It also sets the HELPDIR environment variable, used by run-help, to identify the location of the zsh help files directory.

  • Under Linux, it's: /usr/share/zsh/help
  • Under OS/X and macOS that's: /usr/share/zsh/VVV/help with VVV replaced by the zsh version number.

The logic is inside USRHOME dot/zshrc.zsh file.

Therefore, on most systems you should end-up with the zsh shell providing a help command that shows information on zsh builtin commands.

If it does not work for your system, check the value of DIRHELP. You can set it to the value you need inside your file usrcfg/setfor-all-config.sh

Example on Kali Linux:

Here we can see the use of USRHOME in a Kali Linux system where zsh is the default shell. At first it was setup with the older USRHOME version that did not support help. Then USRHOME is updated with a git pull command and then we can open a new shell where help kill works as expected.

res/zsh-help-on-kali.png

Example on macOS Sonoma

With USRHOME support the help kill command works on macOS zsh.

res/zsh-help-on-macOS.png

CBR -- Single commands to Check, Build or Run

USRHOME supports 3 single letter commands for checking, building and running code: c, b and r. These are command aliases that are installed inside the shell by the use-cbr command (which is an alias itself to usrhome/ibin/envfor-cbr).

The c, b and r commands are aliases to the usrhome/ibin/do-cbr sourced script that detect the mechanism required to perform the required action by inspecting the content of the current directory.

This currently supports the following construction methods:

  • Running a local cbr executable file if one exists. More on this below the table.
  • Building single-file C and C++ programs with GNU make, taking advantage of GNU Make built-in rule for building the single C and C++ programs.
  • Building programs with the 'make' command when the directory holds a 'Makefile' or 'makefile'.
  • Build Rust program with Cargo.
  • Build Rust single main.rs program.

Once installed inside the shell with use-cbr, the following commands are made available:

Command Description
c Check. Perform command(s) required to check the validity of the source code in the current directory.
b Build. Perform command(s) required to build an executable from the source code in the current directory.
r Run. Perform command(s) required to build an executable from the source code in the current directory and run it.

Once you have typed use-cbr, simply cd into the code directory and type one of the 3 letters. For example, type r to compile, link and run a Rust program from the top directory of the Rust program.

If the commands cannot identify how to build the program it reports an error, returning with exit code of 1.

Using a local cbr executable file:

After executing use-cbr, the c, b and r commands check if a local cbr executable file is located in the current directory. If they find one they pass control to it, as described below. If there's none, then the command try to detect how to build the files in the directory with the construction methods described above.

When the cbr executable file is found the commands invoke it passing all arguments to it. The cbr command should expect and support, as their first argument, the letters c, b and r, and should act accordingly.

This can do anything your project requires, like invoking a special build tool with the necessary arguments. It can be useful when CBR currently does not support the construction method you need.

Another use of the cbr executable is to changes the current directory to the directory where the build command must be issued and then re-issue the CBR command from that directory.

For example, assuming you have a project where the build command is issued from the project root directory and that you also want to be able from a sub-directory. To be able to issue the c, b or r command from that sub-directory create a cbr or .cbr executable file inside the sub-directory that contains something like this:

#!/bin/sh
cd ..
source "$USRHOME_DIR/ibin/do-cbr" $1

With this the c, b and r commands can be executed from the project root directory and from its sub-directory.

Using Emacs as a man reader

Anyone that have used Emacs knows that Emacs man support is really good. For instance, with Emacs, you can follow all links that appear in man pages; you essentially have access to a man page browser with access of all Emacs features.

You can use man (or woman) right inside Emacs. But at the shell, the man command will use the default man pager. Being able to open the man pages with Emacs when typing the man command in the shell is what this section is about.

USRHOME provides the use-emacs-for-man alias command that sets up the current shell, replacing the man command by a man function that opens the requested topic inside Emacs. Both the use-emacs-for-man alias command and the man function also accept an option switch that identifies the way Emacs is launched.

To use this, you first execute use-emacs-for-man to setup the shell. Then, when you type the man command inside that shell, the optic is shown inside Emacs.

. Command Description
. use-emacs-for-man [-[gGsStT]]

Install the Emacs-minded man command inside the shell.

By default it sets the Emacs launching mode to the terminal mode. You can change this by using one of the following options:

  • -g : launch Emacs in GUI mode. Use the ge script to do so. It will use the template version of that script located inside usrhome/template/bin/ge unless it finds it on the PATH.
  • -G : same as -g but launches Emacs quicker with less initialization by using Emacs -Q option.
  • -s : uses emacsclient to the Emacs daemon.
    • This checks if the Emacs daemon is already running. If it's not running it starts it, after printing a message stating what it is doing.
    • Before using the man command with the Emacs daemon, you should launch an emacsclient process on something, if that's not already done, otherwise the man command will print an error telling you to start it.
  • -S : same as -s but does not delete an Emacs window after executing the man command. This is normally better when executing the man command from within a shell of the emacsclient itself.
  • -t : launch Emacs in terminal mode in the current shell. This is the default if no option is specified.
  • -T : same as -t but launches Emacs quicker with less initialization by using Emacs -Q option.
.
  • man [-[gGsStT]] TOPIC
  • man -man [OPTIONS] TOPIC

Open Emacs man mode viewer for the specified TOPIC.

  • If no option is identified it launches Emacs as selected by the execution of use-emacs-for-man options.
  • If man is executed with one of the 6 options, it uses the method selected by the option, overriding what was selected by use-emacs-for-man.

If you want to use the system's native man command from a shell where you already executed use-emacs-for-man, then you can use the -man special option, followed by all options you want to pass to the native man command. That executes the native man command with all options passed to it.

The advantage of using the Emacs daemon and an emacsclient are:

  • Speed. Since Emacs is already running, the man command does not have to launch a new Emacs process that has to run through the initialization process; it just opens the man page and renders it (if that has not already been done). Opening the man page is instantaneous this way.
  • Reduced system memory consumption. One Emacs frame is required and can be used by the man command issued from several shells.
  • When the -S option is used, all man pages that have been previously opened are left open inside an emacsclient buffer. They each retain the position where you left them when last looking at them.
  • The Emacs daemon starts with your full initialization; all your configured Emacs features are available.

The advantage of not using the Emacs daemon and emacsclient is that you open a new Emacs process, local to your shell with all its environment variables and you can continue using that instance of Emacs independently from all others (if any). It takes more tie to start but if your initialization system is well done that's normally not excessive and it gives you access to everything you normally use withing Emacs.

With USRHOME, you can take advantage of both methods, happily eating your cake and keep having it!

It is possible to use both methods with multiple shells or inside the same shell by passing the emacs mode option to the man command. You can use several shells and use different method inside each one if you want. Or just use one method. The code is flexible.

Getting help

You can pass the -h or --help options to both use-emacs-for-man and the specialized man function. They will print the usage and return an exit code of 1. The man command also prints a reminder that the native man command is not the one being used.

res/use-emacs-for-man-00.png

Exit Codes

  • On success; 0.
  • On help request: 1
  • On error: 2 or 3.
  • For man -s and -S, when topic is not found: 4.
To Activate it Permanently in a Shell:

You may not always want to type the use-emacs-for-man command. Instead you can add a specific man behaviour permanently inside your shell by sourcing the usrhome/ibin/envfor-emacs-for-man inside your shell startup code. For example, you could add the following code inside your usrcfg/do-user-zshrc.zsh file to activate a man that uses an emacsclient frame:

. "$USRHOME_DIR/ibin/envfor-emacs-for-man" -s

The shells can be "permanently" customized this way by writing the logic that suits you inside your customization for the Z shell and the Bash shell into your usrcfg files.

For example, on a macOS system I use, I activate Homebrew, Rust and the emacs server based man with customized logic that includes the following lines:

export USRHOME_SHOW_PATH_ACTIVATION=1
export USRHOME_PROMPT_SHOW_USR_HOST=1
export USRHOME_PROMPT_MODEL=2
export USRHOME_USE_HOMEBREW=1
. "$USRHOME_DIR_USRCFG/ibin/envfor-rust"
. "$USRHOME_DIR/ibin/envfor-emacs-for-man" -s

We can see this in the following screen-shot:

res/use-emacs-for-man-01.png
Side note:
My PEL project provides extensive information about Emacs (in form of extensive hyperlinked PDF files with a PDF index to a large set of topics and file format/language supports). The help PDF has a section that describe Emacs man and woman support.

Miscellaneous Commands

USRHOME Command Name Description
cls Shortcut for clear; clear the content of the shell window.
diff

USRHOME diff is a shell-based dispatcher program.

  • By default it uses the standard ``/usr/bin/diff``q program
  • You can change this behaviour in the current shell by executing the use-diff command (an alias which sources the envfor-diff script). With it, you can select other programs that will be invoked by the command.
dsize [DPATH] Compute and print the size of all files in the directory tree identified by DPATH, which defaults to the current directory. If the directory has no sub-directories the command counts the bytes of each files in the directory and produces a byte count. Otherwise it uses the du command, which runs faster, and print the size in units of 1024 bytes multiples.
find-dir

Find and print directories DIR inside directory tree ROOT.

Its help is:

Usage: find-dir [--inc-hidden|-H] DIR [ROOT]
       find-dir [-h|--help]

Find and print all directories with name 'DIR'
inside the specified directory tree ('ROOT').

- By default ROOT is the current directory.
- By default exclude all hidden directories (such as .git)
  unless --inc-hidden option is specified.

Exit codes: 0 if at least one directory found.
          : 1 if nothing is found.
          : 2 if the command line is invalid.
flip-to-ln DPATH FNAME

Move file FNAME into directory DPATH and create a symbolic link FNAME that points to its new location inside directory DPATH.

  • Under Linux, where the GNU coreutils ln (>= 8.16) has the -r option switch, the symbolic links are always created relative if they can be.
  • Under macOS if you need to create relative symbolic links you must provide relative FNAME and DNAME arguments.
md Shortcut for mkdir
rd Shortcut for rmdir
mdd DIRPATH A mkdir followed by cd. If DIRPATH has '/', then create intermediate directories as required and print them on stdout.
p3 Shortcut for python3
pngquantf FNAME Compress PNG file identified by FNAME (with or without .png file extension. Uses pngquant.
pstree-for [PID] Print the process tree for specified process ID, PID. If PID is not specified, the command uses the process ID of the current process.

USRHOME Prompt

USRHOME provides control for the Z Shell and Bash prompts as described in this section. USRHOME provides 3 pre-defined prompt models (model 1, 2 and 3) and reserves prompt model number 0 to be user-defined.

Information About Prompt Control Variables

URSHOME provides the following commands to get information about the shell prompt.

USRHOME Command Name Description
info-prompt [-q] Print information about shell's prompt controlling variables. By default it prints the values of all variables. With the -q option it only prints the values of the USRHOME_PROMPT_MODEL and USRHOME_PROMPT_MODEL_OVERRIDE values. The first one shows the value of the default prompt mode, the second one, if set, is the model of the current prompt, overriding the default.

USRHOME prompt model control logic supports the environment variables described here:

Environment variable Description
USRHOME_SLOW_TIMER

On macOS only: when set it forces the use of 1-second resolution timer for the Bash prompt.

This is done by ignoring the potential availability of the GNU coreutils gdate command and use the macOS supplied date command.

You may want to do this if the Bash prompt on macOS runs into a race condition and prints a message similar to:

bash: child setpgid (75144 to 75141): Operation not permitted

This might occur when you are executing a fast command and pipe it into another.

Setting USRHOME_SLOW_TIMER should prevent this problem. You can do it dynamically inside the Bash shell like this:

setenv USRHOME_SLOW_TIMER
bash

Or you can set it inside your usrcfg/setfor-all-config.sh by including the following lines:

USRHOME_SLOW_TIMER=1 export USRHOME_SLOW_TIMER

Prompt Model 0

With the USRHOME_PROMPT_MODEL environment variable set to 0, USRHOME does not configure the zsh prompt and expects the prompt to be set inside the user provided configuration files located inside the usrcfg directory, otherwise it uses the system default.

Prompt Model 1, 2 and 3

These prompt models are predefined prompts that show multiple values in various ways. As these might evolve over time, it's best to try them and see them in your terminal.

The user@host information is shown when enabled. This can be dynamically enabled or disabled with the usrhome-prompt-toggle-usr-host command.

In the following sessions, the command info-prompt -q is used to show which one is the default prompt model and which one is the currently used prompt.

The bash prompts

res/macOS-bash-prompts-01.png

The zsh prompts

res/macOS-zsh-prompts-01.png

Notable prompt features

All provided prompts, show:

  • A leading '>' character,
  • the exit code of the last command, in decimal or hexadecimal,
  • current time in 24-hour HH:MM:SS format,
  • the shell nested level, prefixed with 'L',
  • optional user-name @ host-name,
  • the full or last 3 directory components of the current directory,
  • the shell name (bash, or zsh),
  • the last character is '#' if the current user has root privilege, otherwise the '$' character is used for bash and the '%' character is for zsh.

Some also show the Week day and month date, the number of currently running jobs of the shell.

Prompt model 2 and 3 prints the elapsed time of the last command with millisecond resolution. On macOS without GNU coreutils gdate available the resolution is in seconds.

The zsh prompt can also print extra information:

  • zsh prompt model 1 shows extra information on the right side of the line, there is enough room: the full path of the current directory, and VCS (Git or Mercurial) repository name.
  • The VCS (Git or Mercurial) repository name is shown in all zsh prompts.
    • If the current directory is part of a Git or Mercurial repository, the prompt shows 2 spaces followed by:
      • 'git:' for Git repository and 'hg:' for Mercurial repository,
      • the VCS branch name in parenthesis
      • the VCS repository name.
  • Exit code of error and number of running jobs are also shown in the right hand side in zsh prompts.
    • If the exit code of the last error is not 0, the exit code followed by a red '⨯' character.
    • If the shell has sub-process jobs, the number of jobs is shown, followed by a yellow '⚙' character.

Examples

Some extra examples shown here:

res/zsh-prompt-01.png

Here's an example when the prompt model 2 is selected by user configuration and the user dynamically changes it inside the shell.

res/zsh-prompt-02.png

And here's another example, when the shell with prompt model 2, has two nested instances of suspended Emacs running, in a macOS terminal.

res/zsh-prompt-03.png

When the shell has running background jobs, the USRHOME commands that use exec zsh to re-initialize the Z Shell won't proceed and will print a warning message instead. In the example above the two running process where e the USRHOME name for terminal-based emacs. To be able to change the process prompt, these two suspended Emacs process must first be terminated (by making them active in the foreground again with fg and then closing Emacs). Once there's no background process the usrhome-prompt-toggle-usr-host command can be used.

Showing the shell type helps when capturing commands for logs: it explicitly identifies the shell.

res/zsh-prompt-model-3.png

Prompt Search Regexp

Use the following regular expressions to search a prompt, or to install them in editors, like Emacs, to navigate through prompt lines inside a shell.

The regular expression syntax shown here correspond to the Emacs 'string-format' regular expression syntax, the syntax you can use inside Emacs configuration.

Prompt Emacs Regular Expression
All models ^\(\(zsh\)\|\(bash\)\)[%#$]

Command and Script Organization

USRHOME provides several types of command and scripts, as listed here.

Name format of scripts Type of script Purpose
USRHOME/ibin/do-CMD Sourced script Meant to be invoked by alias command CMD
USRHOME/ibin/setfor-CMD Sourced script Meant to be invoked by alias command CMD
USRHOME/ibin/envfor-ENV Sourced script Meant to be invoked by alias command use-ENV
USRHOME/bin/... Shell script A regular script that can be invoked directly.

The commands alias are all sourcing a sourced script that injects or modifies something inside the current running shell. The source scripts all have names that start with one of the identified prefixes: setfor- or envfor-.

The setfor- sourced scripts are used by various USRHOME commands that control the shell, such as usrhome-shell-toggle-tracing and usrhome-prompt-toggle-usr-host.

The envfor-ENV sourced scripts are used by the equivalent use-ENV command. These commands set the shell for the environment identified by the ENV suffix. The idea is that when you start a shell it comes with a minimal environment. You can then activate a given environment by issuing the corresponding use- command. For example, assuming that you want to use various tools for the Erlang, Factor, Rust or Zig programming languages but separately, in each shells, you would use the use-erlang, use-factor, use-rust and use-zig commands that source their corresponding source scripts that update the PATH and other environment variables that are necessary for the environment.

As USRHOME grows, I will be adding several of these environment setting scripts and commands to support various Operating Systems.

File Naming Convention

File Name Format Description
Command aliases

The command aliases must be defined in shell sourced files with the alias shell builtin. For example:

alias usrhome='source $USRHOME_DIR/ibin/do-usrhome'
sh4-PROJECT

Command alias to setup the shell for a specific project.

  • This is typically an alias to source a corresponding shell sourced file with a name sh4--PROJECT for the given PROJECT (notice the double dashes in the name of the sourced file).
  • A sh4--PROJECT file in turns sets up the shell with all the tools required for working on this project, and perhaps also a named Emacs server for the project. To set up the shell, the file typically sources a set of envfor-ENV files, each one setting the shell for their specific information.
use-ENV

Command alias that sets up the shell environment for a specific tool.

  • This is typically an alias to source a corresponding shell sourced file with the name envfor-ENV for the given ENV.
  • The file typically installs commands in the shell by either adding a directory to the PATH or defining these commands as shell commands injected inside the current shell.
Sourced Script

All modifications to the current shell are performed by logic stored inside shell script files that must be sourced. The base name of these files follow the following convention.

  • The syntax used by the script code of these files must support both the Z Shell and Bash, since they are both supported by USRHOME.
  • These files are typically stored inside usrhome/ibin or usrcfg/ibin directories which are never placed inside the shell PATH. They are accessed via explicit commands stored in other sourced file which include the complete path name using one of the USRHOME environment variable (typically USRHOME_DIR or USRHOME_DIR_USRCFG).
sh4--PROJECT Sourced file typically invoked by its corresponding sh4-PROJECT file to set up the shell for project PROJECT.
envfor-ENV Sourced file typically invoked by its corresponding use-ENV alias command to set up the shell environment for a specific tool.
do-CMD Sourced file typically invoked by it corresponding CMD shell command to inject something inside the current shell.
setfor-SHELL-SETUP

Sourced file that is part of the shell setup logic that comes from USRHOME or from the user specific usrcfg directory. See the diagrams inside the following sections:

The Z Shell Startup, Dot Files and User Configuration

The Z Shell has five different user configuration files:

  • ~/.zshenv
  • ~/.zprofile
  • ~/.zshrc
  • ~/.zlogin
  • ~/.zlogout

USRHOME implements its own copy of each of these files, stored in the usrhome/dot directory. The files are named differently, without a leading period and with a .zsh file extension. That simplifies editing and management on these files on various environments. Several tools require a special option to process hidden files; it's not needed for these files since they are not hidden.

However, to be used, USRHOME setup places them inside the user home directory, creating hidden symlinks to the files. The result is the following:

Symbolic link USRHOME File Identified
~/.zshenv usrhome/dot/zshenv.zsh
~/.zprofile usrhome/dot/zprofile./zsh
~/.zshrc usrhome/dot/zshrc.zsh
~/.zlogin usrhome/dot/zlogin.zsh
~/.zlogout usrhome/dot/zlogout.zsh

The files sourced by the Z Shell depend on how the Z Shell is started. The files sourced by USRHOME take advantage of that behaviour to inject the user configuration, as shown in the following diagram portion.

res/zsh-startup-01.png
  • The ~/zshenv is sourced in all case. Therefore the usrhome/dot/zshenv.zsh sources the user's basic configuration file (usrcfg/setfor-all-config.sh) that identifies the main USRHOME configuration features.
  • The file usrhome/ibin/setfor-path controls adding extra directories in the PATH; the directories used by USRHOME and some other. That file is optionally sourced by the usrhome/dot/zprofile.zsh for a login shell and by the usrhome/dot/zshrc.zsh in a sub-shell. For the login shell the PATH is modified only when the USRHOME_CONFIG_AT_LOGIN variable is set to 1.
  • Since the usrhome/dot/zshrc.zsh is used both in the login and the sub-shell, it's the file that sources the usrhome/ibin/setfor-zsh-alias to inject the USRHOME alias commands and sell functions inside the shell. That's also the file that sanitizes the PATH; it removes empty entries and duplicates if there's any. And in that case it prints a warning. That's an indication to take a look at your configuration files (or to the application that launched a sub-shell).

The user can provide extra startup logic for the Z Shell. USRHOME Z Shell startup code sources the following user configuration files stored in the user managed usrcfg directory:

  • usrcfg/do-user-zprofile.zsh
  • usrcfg/do-user-zshrc.zsh

Each of these files is sourced if they exist. In turn these files could source files for the specific node if the user wants to support several hosts. The diagram shows the order in which the files are sourced.

The Z and Bash Shell Startup, Dot Files and User Configuration

USRHOME supports the Bash and the Z shell and currently concentrates on using these shells on user development computers (as opposed to servers). To support both shells, more configuration files are required and some logic is the same for both shells. The following diagram shows all files currently used in the USRHOME system to support both shells.

USRHOME is built on the principle that shell configuration logic is provided by two sets of files:

  • the files provided by the USRHOME repository, and
  • the files provided by another, user-provided, repository: the usrcfg repository.

The files provided by USRHOME provides the basic infra-structure logic and some commands that will be available in the shells. The content of the files are not meant to be modified by the users (unless someone wants to change or add a feature to USRHOME).

The user-specific logic is stored in the files stored in the usrcfg directory tree.

Since the reason for the USRHOME project is to ease the shell configuration setup and distribution of many computers or Virtual Machines without having to use containers, the usrcfg directory tree should also be a VCS repository controlled by the user (and kept private). It then becomes possible to keep an history of the shell configuration of multiple computers inside these 2 repositories and it becomes easy to set computers by cloning or updating the two repositories inside these computers.

The usrcfg stores logic that is common to all the users system in the files located in its root directory. The logic that is specific to each computer must be stored inside a sub-directory of the usrcfg/node directory.

The following diagram shows which configuration file is sourced when the Bash and Z shell start as a login or as a sub-shell.

res/zsh-bash-startup-01.png

Activate Tracing of the Sourcing of the Shell Configuration Files

By setting the value of USRHOME_TRACE_SHELL_CONFIG to 1 inside your usrcfg/setfor-all-config.sh file you activate USRHOME's shell configuration file tracing. Then when you open a new shell inside a terminal, or create a sub-shell, you can see which file is sourced.

You can also set the value of USRHOME_TRACE_SHELL_CONFIG to the name of a file located inside an existing directory. That activates the tracing to the shell stdout as for the value 1 but it also activates storing the trace lines inside the specified file.

With all usrcfg files existing, this is what you'd see from macOS that uses the Z Shell as the default shell when you open a new terminal and then create a sub-shell inside it. The name of the environment variables are shown instead of the real path.

res/zsh-tracing-startup-01.png

For comparison, here's the same inside shells started from within a terminal based instance of Emacs with two shells, one running inside a shell-mode buffer and another inside a term-mode buffer. Notice that the Z Shell started inside Emacs are sub-shells and therefore only execute the corresponding Z Shell configuration files for that.

res/zsh-tracing-startup-term-emacs.png

From a graphical version of Emacs started from the system (and not from a shell):

res/zsh-tracing-gr-emacs.png

And a version of Aquamacs started from the system. In that case you can see that the USRHOME logic detects and reports redundant entries in the PATH that is injected by the Aquamacs logic and then corrects them.

res/zsh-tracing-aquamacs.png

When the USRHOME_TRACE_SHELL_CONFIG is set to 0 instead of 1, USRHOME startup configuration files do not display the entire warning. It just mentions that USRHOME sanitized the PATH and how to see more as we can see here:

res/zsh-tracing-aquamacs-02.png

USRHOME Security Checking

USRHOME reports the security issues by checking for the presence of compromised command line tools in the PATH. The list of detected compromised tools is:

Here's what the shell would show when the compromised tool is present in the system.

res/xz-vulnerability.png

Adding Your Own Environment Customization to your Shell

You will most probably want to add features to your shells, over what USRHOME provides. USRHOME provides several mechanism to do that, described in the following sections with examples and files located in the setup/template directory you can use as examples.

The use- commands -- Inject something in your local shell

The idea here is to provide a set of sourced scripts and corresponding commands to source them. One set for each feature you want to inject into your shell. Something like providing access to a different implementation of a command available to the Operating System, or adding support for the tools required for a programming language.

The method:
Add a use-ENV alias command that sources a envfor-ENV script, where ENV is the name of the environment concept. Add the alias statement into the usrcfg/do-user-zshrc.zsh file. Store the envfor-ENV script inside the usrcfg directory.

Examples follow.

use-curl-hb -- Activate Homebrew version of curl in the current shell.

The version of curl available on macOS is often relatively old and may not incorporate the latest vulnerability fixes. You may want to install the latest available from Homebrew but once you install it it will warn you that installing it permanently might cause problems with macOS.

A solution to this is to install the files ion your system but not install the symlinks and not put it your your system's PATH. Homebrew does that. Now if you want to use Homebrew's version of curl you need to ensure that it will be piked up in the PATH before the system's one.

To do that we can place the following statement inside the usrcfg/do-user-zshrc.zsh file:

alias use-curl-hb='source $USRHOME_DIR_USRCFG/envfor-curl-hb'

And we store the logic we need into the usrcfg/envfor-curl-hb file. In this specific case, there's not much. Just this:

export PATH="/opt/homebrew/opt/curl/bin:$PATH"

When we open a new Z Shell we can see the impact:

res/use-curl-hb.png

There's no impact in any other shells, and macOS continues to use its own version of curl. You can open another shell and it will use the native version unless you execute the use-curl-hb command.

use-rust -- Activate Rust programming environment in current shell

If you want to use the Rust programming language you most probably need to install it in your system. The default mechanism is to install it in the system and each shell will have access to it. You may also want to only limit it to one given shell and start all tools from that shell (or shells). That what the use-rust command will do.

The first step is to install Rust and Cargo as described in it the Rust installation procedure, with:

curl https://sh.rustup.rs -sSf | sh

Once it's done, you can use the git diff command to see what that changed into your shell configuration that is now stored inside the USRHOME directory tree.

res/rust-install.png

The Rust installation added the sourcing of "$HOME/.cargo/env" to your USRHOME dot/zshenv.zsh file. Recall that the ~/.zshenv now the USRHOME dot/zshenv.zsh is sourced every time a terminal opens a shell, at the beginning, before everything else. It also sources it when a sub-shell is opened. Looking into the $HOME/.cargo/env we can see that it conditionally prepends the $HOME/.cargo/bin directory to the PATH. At least it won't do it several times. But if you append that inside your Z Shell configuration it will be available to all processes once you restart your system. It might be what you want. Or not.

If you just want to add Rust support in selected shells, then create a use-rust command.

  • Remove the extra code that was appended to your USRHOME dot/zshenv.zsh file and place it inside a envfor-rust script located inside your usrcfg directory. At the same time add a little bit more to provide more info:

    . "$HOME/.cargo/env"
    rustv="$(rustc --version)"
    echo "--- Rust $rustv Installed in shell"
  • Add the use-rust alias to your usrcfg/do-user-zshrc.zsh file:

    alias use-rust='source $USRHOME_DIR_USRCFG/envfor-rust'

Now you can inject Rust support by executing the use-rust command:

res/use-rust.png

As you can see no change is required in the files supplied by the USRHOME project. The customization is done inside your files, located in the usrcfg directory tree. That directory tree should also be under the control of a version control system, like Git or anything else. I also use Mercurial for that purpose as you can see below.

res/use-rust-02.png

Adding Permanent Environments to all Shells

In some cases you may decide to add a feature to the system shell and all shell instances. This way you won't have to type the required use- command into each shell that requires it.

You can do that too with USRHOME. And there are several ways to do it; add the sourcing of the corresponding envfor- file from one of the .zsh files in the usrcfg. Usually you will probably want to do that from the usrcfg/do-user-zshrc.zsh.

With envfor-rust sourced inside the usrcfg/do-user-zshrc.zsh file, Rust support is installed automatically inside all shells, including the system Z Shell as we can see:

  • from a Z Shell launched from Terminal.app:

    res/use-rust-03.png
  • from a Z Shell opened inside a shell-mode terminal-type Emacs buffer:

    res/use-rust-in-e.png
  • from a Z Shell opened inside a shell-mode graphical-type Emacs buffer:

    res/use-rust-in-ge.png
  • from a Z Shell opened inside a shell-mode Aquamacs buffer:

    res/use-rust-in-aquamacs.png

Using USRHOME on Kali Linux

Kali Linux uses zsh as the default shell. It has it's own prompt definition with several Z Shell extensions enabled, which the USRHOME default shell does not have yet.

You can still use USRHOME on Kali Linux and take advantage of the USRHOME commands and philosophy of storing the USRHOME main code and the local shell customization inside the usrcfg directory. That can also be stored inside a repository. In this example, the usrcfg files are stored inside a Mercurial repository. The logic in the various files support multiple target environment, which they select by checking the host name and other values.

This way, I can centralize the shell setting of all computers or VMs I use inside a single repository that I clone inside the usrcfg directory of these computers and VMs. I can design the logic once, specialize it for various environments and distribute it through the VCS.

Here's a Kali Linux terminal with the Z shell using USRHOME selecting the original Kali Linux Z Shell configuration (moved into the usrcfg/do-user-zshrc.zsh file and selected based on the USRHOME prompt model value):

res/on-kali-linux.png

And then, after changing the color scheme of Kali Linux terminal, two terminals, one running the terminal version of Emacs launched with an alias to emacs -nw and the graphical version of Emacs launched from the shell with a shell function that captures the current working directory and runs in background. You can see the prompts inside the Emacs shell-mode and term-mode buffers.

res/on-kali-linux-02.png

Using USRHOME on macOS

On macOS several tools that are available on Linux are missing.

I am using Homebrew to install these tools. When used on macOS running on Apple Silicon CPU, Homebrew does require sudo access because it places all files inside the /opt/homebrew directory tree, with /opt/homebrew/bin the location of the executable files (or symlinks to the executable files). This directory is not on PATH unless you place it. USRHOME adds it for macOS.

USRHOME provides several features to enhance the command line experience on macOS without affecting macOS default environment. It becomes possible to use macOS as it was when first installed or use it with the USRHOME provided features inside the USRHOME extended shells.

More information about the extra features are described in the following sections.

Using GCC on macOS

The following commands specializes the shell to use a specific version of the GCC tool chain inside the shell. That shell can then build using the specified tool chain instead of the Apple-supplied Clang tool chain.

. Command Description
. use-gcc14 [--quiet]

Installs GCC 14 tool chain inside the current directory.

  • By default it is a little verbose, printing the actual version of GCC installed, the resulting PATH and MANPATH. You can use the --quiet option; it will only print one line.
  • It can only be executed once inside a shell. It will print an error if you try to run it again.
  • It requires a ~/bin directory to exists.
  • The first time executed, it checks for the presence of a ~/bin/gcc-14 directory and other files. If these are not found, it will print an error message showing that you must execute the script create-gcc-as-gcc14.sh.
    • create-gcc-as-gcc14.sh checks the requirements, which includes the Homebrew-installed GCC 14. If it is not found the script will tell you to install it with the brew install gcc@14 command.
    • Once this is done it will create the required symbolic link files inside your ~/bin/gcc-14 directory which will later be placed in your PATH.
    • Upon success, create-gcc-as-gcc14.sh will instruct you to execute use-gcc14 again.
  • The use-gcc14 command is a an alias that sources the usrhome/ibin/envfor-gcc14-on-macos script. That script puts the ~/bin/gcc-14 at the beginning of the shell's PATH, effectively activating the GCC commands.

Feedback's Welcome!

If you stumble on this page and find this project interesting but falling short somewhere, let me know. Create an issue or propose a change or addition through a pull-request.

Thanks!