hello,

Please consider these two patches for inclusion in bash to support
storing shell initialisation files (profile, bashrc) in a subdirectory
of ~/.config/ as most programs do these days.

I'm happy to make changes to address any feedback.

Even if you'd prefer not to apply the second patch, applying the first
patch is a nice cleanup and would make it easier for distributions
such as Fedora to apply the second patch for themselves.

Thank you very much for your consideration,

Allison
From 282befe3579897174288075810a6c1d89df7a29f Mon Sep 17 00:00:00 2001
From: Allison Karlitskaya <allison.karlitsk...@redhat.com>
Date: Fri, 7 May 2021 11:11:55 +0200
Subject: [PATCH 2/2] shell: add ~/.config/bash/ startup script options

Introduce an alternate location for storing a profile and bashrc file,
inside ~/.config/bash.

This is mostly compatible with the XDG Base Directory Specification[1],
but doesn't support expanding the XDG_CONFIG_HOME environment variable,
which would require a larger patch with string manipulation/pasting.

[1] https://specifications.freedesktop.org/basedir-spec/
---
 doc/bash.1 | 21 ++++++++++++++-------
 shell.c    |  5 +++--
 2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/doc/bash.1 b/doc/bash.1
index 5af7d428..69aa9853 100644
--- a/doc/bash.1
+++ b/doc/bash.1
@@ -188,6 +188,8 @@ Display a usage message on standard output and exit successfully.
 Execute commands from
 .I file
 instead of the standard personal initialization file
+.I ~/.config/bash/bashrc
+or
 .I ~/.bashrc
 if the shell is interactive (see
 .SM
@@ -219,6 +221,8 @@ below).
 .TP
 .B \-\-norc
 Do not read and execute the personal initialization file
+.I ~/.config/bash/bashrc
+or
 .I ~/.bashrc
 if the shell is interactive.
 This option is on by default if the shell is invoked as
@@ -318,9 +322,10 @@ is invoked as an interactive login shell, or as a non-interactive shell
 with the \fB\-\-login\fP option, it first reads and
 executes commands from the file \fI/etc/profile\fP, if that
 file exists.
-After reading that file, it looks for \fI~/.bash_profile\fP,
-\fI~/.bash_login\fP, and \fI~/.profile\fP, in that order, and reads
-and executes commands from the first one that exists and is readable.
+After reading that file, it looks for \fI~/.config/bash/profile\fP,
+\fI~/.bash_profile\fP, \fI~/.bash_login\fP, and \fI~/.profile\fP, in that
+order, and reads and executes commands from the first one that exists and
+is readable.
 The
 .B \-\-noprofile
 option may be used when the shell is started to inhibit this behavior.
@@ -333,8 +338,9 @@ exists.
 .PP
 When an interactive shell that is not a login shell is started,
 .B bash
-reads and executes commands from \fI~/.bashrc\fP, if that file exists.
-This may be inhibited by using the
+looks for \fI~/.config/bash/bashrc\fP, and \fI~/.bashrc\fP, in that
+order, and reads and executes commands from the first one that exists and
+is readable.  This may be inhibited by using the
 .B \-\-norc
 option.
 The \fB\-\-rcfile\fP \fIfile\fP option will force
@@ -424,8 +430,9 @@ connected to a network connection, as when executed by the remote shell
 daemon, usually \fIrshd\fP, or the secure shell daemon \fIsshd\fP.
 If
 .B bash
-determines it is being run in this fashion, it reads and executes
-commands from \fI~/.bashrc\fP, if that file exists and is readable.
+determines it is being run in this fashion, it reads and executes commands
+from the first one of \fI~/.config/bash/bashrc\fP, and \fI~/.bashrc\fP,
+which exists and is readable.
 It will not do this if invoked as \fBsh\fP.
 The
 .B \-\-norc
diff --git a/shell.c b/shell.c
index 6327e72d..c14c1844 100644
--- a/shell.c
+++ b/shell.c
@@ -1104,7 +1104,8 @@ execute_profile ()
 
   if (!act_like_sh)
     {
-      if (maybe_execute_file ("~/.bash_profile", 1) ||
+      if (maybe_execute_file ("~/.config/bash/profile", 1) ||
+          maybe_execute_file ("~/.bash_profile", 1) ||
           maybe_execute_file ("~/.bash_login", 1))
 	return;
     }
@@ -1125,7 +1126,7 @@ execute_bashrc ()
 
   if (bashrc_file)
     maybe_execute_file (bashrc_file, 1);
-  else
+  else if (maybe_execute_file ("~/.config/bash/bashrc", 1) == 0)
     maybe_execute_file (DEFAULT_BASHRC, 1);
 }
 
-- 
2.31.1

From 5d6a04c8594f9441b12c1a7485a4106b03bd2b03 Mon Sep 17 00:00:00 2001
From: Allison Karlitskaya <allison.karlitsk...@redhat.com>
Date: Fri, 7 May 2021 10:59:09 +0200
Subject: [PATCH 1/2] shell: reduce duplication with startup files

The logic for deciding which startup files to run currently includes two
separate copies of the bashrc (system vs homedir), and the profile
(system vs homedir, posix vs bash).

Create two separate functions to handle the "profile" vs "bashrc" cases
without duplicating the file lists.

Meanwhile, the handling of the `--rcfile` option works by preseeding the
option value to the default of "~/.bashrc" and overriding it when the
user specifies the option.  That works nicely, but only because we only
consider exactly one possible bashrc file (which will stop being true
with the following commit).  Rework this a little to make the `--rcfile`
option act as an override, which is set to NULL in case the flag isn't
specified.  In that case, we will fall back to the default bashrc.

This commit is a pure refactor.  It introduces no functional changes.
---
 shell.c | 85 +++++++++++++++++++++++++++------------------------------
 1 file changed, 40 insertions(+), 45 deletions(-)

diff --git a/shell.c b/shell.c
index ce8087f7..6327e72d 100644
--- a/shell.c
+++ b/shell.c
@@ -192,7 +192,7 @@ int have_devfd = 0;
 #endif
 
 /* The name of the .(shell)rc file. */
-static char *bashrc_file = DEFAULT_BASHRC;
+static char *bashrc_file;
 
 /* Non-zero means to act more like the Bourne shell on startup. */
 static int act_like_sh;
@@ -1095,6 +1095,40 @@ execute_env_file (env_file)
     }
 }
 
+/* Execute /etc/profile and one of the personal login shell
+   initialization files. */
+static void
+execute_profile ()
+{
+  maybe_execute_file (SYS_PROFILE, 1);
+
+  if (!act_like_sh)
+    {
+      if (maybe_execute_file ("~/.bash_profile", 1) ||
+          maybe_execute_file ("~/.bash_login", 1))
+	return;
+    }
+
+  maybe_execute_file ("~/.profile", 1);
+}
+
+static void
+execute_bashrc ()
+{
+#ifdef SYS_BASHRC
+#  if defined (__OPENNT)
+  maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
+#  else
+  maybe_execute_file (SYS_BASHRC, 1);
+#  endif
+#endif
+
+  if (bashrc_file)
+    maybe_execute_file (bashrc_file, 1);
+  else
+    maybe_execute_file (DEFAULT_BASHRC, 1);
+}
+
 static void
 run_startup_files ()
 {
@@ -1117,17 +1151,7 @@ run_startup_files ()
       /* If we were run by sshd or we think we were run by rshd, execute
 	 ~/.bashrc if we are a top-level shell. */
       if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2)
-	{
-#ifdef SYS_BASHRC
-#  if defined (__OPENNT)
-	  maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
-#  else
-	  maybe_execute_file (SYS_BASHRC, 1);
-#  endif
-#endif
-	  maybe_execute_file (bashrc_file, 1);
-	  return;
-	}
+        execute_bashrc ();
     }
 
 #if defined (JOB_CONTROL)
@@ -1150,18 +1174,8 @@ run_startup_files ()
       /* We don't execute .bashrc for login shells. */
       no_rc++;
 
-      /* Execute /etc/profile and one of the personal login shell
-	 initialization files. */
       if (no_profile == 0)
-	{
-	  maybe_execute_file (SYS_PROFILE, 1);
-
-	  if (act_like_sh)	/* sh */
-	    maybe_execute_file ("~/.profile", 1);
-	  else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
-		   (maybe_execute_file ("~/.bash_login", 1) == 0))	/* bash */
-	    maybe_execute_file ("~/.profile", 1);
-	}
+	execute_profile ();
 
       sourced_login = 1;
     }
@@ -1186,32 +1200,13 @@ run_startup_files ()
 	  /* We don't execute .bashrc for login shells. */
 	  no_rc++;
 
-	  /* Execute /etc/profile and one of the personal login shell
-	     initialization files. */
 	  if (no_profile == 0)
-	    {
-	      maybe_execute_file (SYS_PROFILE, 1);
-
-	      if (act_like_sh)	/* sh */
-		maybe_execute_file ("~/.profile", 1);
-	      else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) &&
-		       (maybe_execute_file ("~/.bash_login", 1) == 0))	/* bash */
-		maybe_execute_file ("~/.profile", 1);
-	    }
+	    execute_profile ();
 	}
 
       /* bash */
       if (act_like_sh == 0 && no_rc == 0)
-	{
-#ifdef SYS_BASHRC
-#  if defined (__OPENNT)
-	  maybe_execute_file (_prefixInstallPath(SYS_BASHRC, NULL, 0), 1);
-#  else
-	  maybe_execute_file (SYS_BASHRC, 1);
-#  endif
-#endif
-	  maybe_execute_file (bashrc_file, 1);
-	}
+        execute_bashrc ();
       /* sh */
       else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0)
 	execute_env_file (get_string_value ("ENV"));
@@ -2007,7 +2002,7 @@ shell_reinitialize ()
 
   /* Ensure that the default startup file is used.  (Except that we don't
      execute this file for reinitialized shells). */
-  bashrc_file = DEFAULT_BASHRC;
+  bashrc_file = NULL;
 
   /* Delete all variables and functions.  They will be reinitialized when
      the environment is parsed. */
-- 
2.31.1

Reply via email to