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