1# This module defines global configuration for the Bash shell, in
2# particular /etc/bashrc and /etc/profile.
3
4{
5 config,
6 lib,
7 pkgs,
8 ...
9}:
10
11let
12
13 cfge = config.environment;
14
15 cfg = config.programs.bash;
16
17 bashAliases = builtins.concatStringsSep "\n" (
18 lib.mapAttrsToList (k: v: "alias -- ${k}=${lib.escapeShellArg v}") (
19 lib.filterAttrs (k: v: v != null) cfg.shellAliases
20 )
21 );
22
23in
24
25{
26
27 options = {
28
29 programs.bash = {
30
31 enable = lib.mkOption {
32 default = true;
33 description = ''
34 Whenever to configure Bash as an interactive shell.
35 Note that this tries to make Bash the default
36 {option}`users.defaultUserShell`,
37 which in turn means that you might need to explicitly
38 set this variable if you have another shell configured
39 with NixOS.
40 '';
41 type = lib.types.bool;
42 };
43
44 shellAliases = lib.mkOption {
45 default = { };
46 description = ''
47 Set of aliases for bash shell, which overrides {option}`environment.shellAliases`.
48 See {option}`environment.shellAliases` for an option format description.
49 '';
50 type = with lib.types; attrsOf (nullOr (either str path));
51 };
52
53 shellInit = lib.mkOption {
54 default = "";
55 description = ''
56 Shell script code called during bash shell initialisation.
57 '';
58 type = lib.types.lines;
59 };
60
61 loginShellInit = lib.mkOption {
62 default = "";
63 description = ''
64 Shell script code called during login bash shell initialisation.
65 '';
66 type = lib.types.lines;
67 };
68
69 interactiveShellInit = lib.mkOption {
70 default = "";
71 description = ''
72 Shell script code called during interactive bash shell initialisation.
73 '';
74 type = lib.types.lines;
75 };
76
77 promptInit = lib.mkOption {
78 default = ''
79 # Provide a nice prompt if the terminal supports it.
80 if [ "$TERM" != "dumb" ] || [ -n "$INSIDE_EMACS" ]; then
81 PROMPT_COLOR="1;31m"
82 ((UID)) && PROMPT_COLOR="1;32m"
83 if [ -n "$INSIDE_EMACS" ]; then
84 # Emacs term mode doesn't support xterm title escape sequence (\e]0;)
85 PS1="\n\[\033[$PROMPT_COLOR\][\u@\h:\w]\\$\[\033[0m\] "
86 else
87 PS1="\n\[\033[$PROMPT_COLOR\][\[\e]0;\u@\h: \w\a\]\u@\h:\w]\\$\[\033[0m\] "
88 fi
89 if test "$TERM" = "xterm"; then
90 PS1="\[\033]2;\h:\u:\w\007\]$PS1"
91 fi
92 fi
93 '';
94 description = ''
95 Shell script code used to initialise the bash prompt.
96 '';
97 type = lib.types.lines;
98 };
99
100 promptPluginInit = lib.mkOption {
101 default = "";
102 description = ''
103 Shell script code used to initialise bash prompt plugins.
104 '';
105 type = lib.types.lines;
106 internal = true;
107 };
108
109 logout = lib.mkOption {
110 # Reset the title bar when logging out. This protects against a remote
111 # NixOS system clobbering your local terminal's title bar when you SSH
112 # into the remote NixOS system and then log out.
113 #
114 # For more details, see: https://superuser.com/a/339946
115 default = ''
116 printf '\e]0;\a'
117 '';
118 description = ''
119 Shell script code called during login bash shell logout.
120 '';
121 type = lib.types.lines;
122 };
123 };
124
125 };
126
127 config = lib.mkIf cfg.enable {
128
129 programs.bash = {
130
131 shellAliases = builtins.mapAttrs (name: lib.mkDefault) cfge.shellAliases;
132
133 shellInit = ''
134 if [ -z "$__NIXOS_SET_ENVIRONMENT_DONE" ]; then
135 . ${config.system.build.setEnvironment}
136 fi
137
138 ${cfge.shellInit}
139 '';
140
141 loginShellInit = cfge.loginShellInit;
142
143 interactiveShellInit = ''
144 # Check the window size after every command.
145 shopt -s checkwinsize
146
147 # Disable hashing (i.e. caching) of command lookups.
148 set +h
149
150 ${cfg.promptInit}
151 ${cfg.promptPluginInit}
152 ${bashAliases}
153
154 ${cfge.interactiveShellInit}
155 '';
156
157 };
158
159 environment.etc.profile.text = ''
160 # /etc/profile: DO NOT EDIT -- this file has been generated automatically.
161 # This file is read for login shells.
162
163 # Only execute this file once per shell.
164 if [ -n "$__ETC_PROFILE_SOURCED" ]; then return; fi
165 __ETC_PROFILE_SOURCED=1
166
167 # Prevent this file from being sourced by interactive non-login child shells.
168 export __ETC_PROFILE_DONE=1
169
170 ${cfg.shellInit}
171 ${cfg.loginShellInit}
172
173 # Read system-wide modifications.
174 if test -f /etc/profile.local; then
175 . /etc/profile.local
176 fi
177
178 if [ -n "''${BASH_VERSION:-}" ]; then
179 . /etc/bashrc
180 fi
181 '';
182
183 environment.etc.bashrc.text = ''
184 # /etc/bashrc: DO NOT EDIT -- this file has been generated automatically.
185
186 # Only execute this file once per shell.
187 if [ -n "$__ETC_BASHRC_SOURCED" ] || [ -n "$NOSYSBASHRC" ]; then return; fi
188 __ETC_BASHRC_SOURCED=1
189
190 # If the profile was not loaded in a parent process, source
191 # it. But otherwise don't do it because we don't want to
192 # clobber overridden values of $PATH, etc.
193 if [ -z "$__ETC_PROFILE_DONE" ]; then
194 . /etc/profile
195 fi
196
197 # We are not always an interactive shell.
198 if [ -n "$PS1" ]; then
199 ${cfg.interactiveShellInit}
200 fi
201
202 # Read system-wide modifications.
203 if test -f /etc/bashrc.local; then
204 . /etc/bashrc.local
205 fi
206 '';
207
208 environment.etc.bash_logout.text = ''
209 # /etc/bash_logout: DO NOT EDIT -- this file has been generated automatically.
210
211 # Only execute this file once per shell.
212 if [ -n "$__ETC_BASHLOGOUT_SOURCED" ] || [ -n "$NOSYSBASHLOGOUT" ]; then return; fi
213 __ETC_BASHLOGOUT_SOURCED=1
214
215 ${cfg.logout}
216
217 # Read system-wide modifications.
218 if test -f /etc/bash_logout.local; then
219 . /etc/bash_logout.local
220 fi
221 '';
222
223 # Configuration for readline in bash. We use "option default"
224 # priority to allow user override using both .text and .source.
225 environment.etc.inputrc.source = lib.mkOptionDefault ./inputrc;
226
227 users.defaultUserShell = lib.mkDefault pkgs.bashInteractive;
228
229 environment.pathsToLink = lib.optionals cfg.completion.enable [
230 "/etc/bash_completion.d"
231 "/share/bash-completion"
232 ];
233
234 environment.shells = [
235 "/run/current-system/sw/bin/bash"
236 "/run/current-system/sw/bin/sh"
237 "${pkgs.bashInteractive}/bin/bash"
238 "${pkgs.bashInteractive}/bin/sh"
239 ];
240
241 };
242
243}