| 1 | --- |
| 2 | type: none |
| 3 | identifier: recover-linux-shell |
| 4 | title: Recovering a Linux desktop with a misconfigured shell |
| 5 | description: How to fix a custom shell when your terminal can't open. |
| 6 | datestring: 2022-11-10 |
| 7 | banner_image: /static/images/esp32.jpg |
| 8 | links: |
| 9 | chsh: https://man7.org/linux/man-pages/man1/chsh.1.html |
| 10 | xonsh: https://xon.sh/ |
| 11 | Virtual consoles: https://www.wikiwand.com/en/Virtual_console |
| 12 | /etc/passwd: https://man7.org/linux/man-pages/man5/passwd.5.html |
| 13 | --- |
| 14 |
|
| 15 | Suppose you’ve used the `chsh` command to change your login shell in the past |
| 16 | and something has gone wrong to the point that your custom shell executable is |
| 17 | nonexistent or no longer functions properly. Opening a new terminal results in |
| 18 | the window closing immediately following a fatal error, or you can’t log in to |
| 19 | your desktop entirely. For me, this happened with `xonsh` (a great amalgam of |
| 20 | Python and Bash) when upgrading between Ubuntu versions, as the installed |
| 21 | Python library fell out of the system path. There are a few methods, however, |
| 22 | to regain access to a functioning shell. |
| 23 |
|
| 24 | # Gaining access to a functioning shell |
| 25 |
|
| 26 | ## Method 1(a): Application launching |
| 27 |
|
| 28 | This method assumes the following: |
| 29 |
|
| 30 | - You are still signed in to your semi-functioning desktop environment (DE) |
| 31 | - You have a functioning terminal emulator and shell installed on your system |
| 32 | - Your DE offers application launching |
| 33 |
|
| 34 | This one is pretty self-explanatory. Terminal emulators can be fed command-line |
| 35 | arguments to skip shell loading entirely and perform direct file execution. You |
| 36 | can use this option to load a shell other than your user’s default shell, as |
| 37 | shells are just executable files. Here are some example commands to load Bash |
| 38 | with different terminals, bypassing your login shell: |
| 39 |
|
| 40 | ```bash |
| 41 | xterm -e /usr/bin/env bash |
| 42 | xfce4-terminal -e /usr/bin/env bash |
| 43 | gnome-terminal -- /usr/bin/env bash |
| 44 | ``` |
| 45 |
|
| 46 | If your DE offers application launching, you can execute the appropriate |
| 47 | command for your terminal emulator and (functional) shell of choice. The |
| 48 | shortcut for application launching on Gnome and XFCE is `<Alt><F2>`. On KDE, |
| 49 | it’s `<Alt><F1>`, and on i3, which uses dmenu, it’s `<Ctrl>D`. For other |
| 50 | desktop environments with application launchers, check which you should use in |
| 51 | the related documentation. |
| 52 |
|
| 53 | ## Method 1(b): GUI-based file execution |
| 54 |
|
| 55 | This is an alternative method to 1(a), assuming: |
| 56 |
|
| 57 | - You are still signed in to your semi-functioning desktop environment (DE) |
| 58 | - Your DE *does not* have application launching, or it doesn’t work for some |
| 59 | reason |
| 60 | - You have a functioning terminal emulator and shell installed on your system |
| 61 | - Your GUI file browser offers direct file execution without terminal |
| 62 |
|
| 63 | Essentially, you create a file like the following, using the appropriate |
| 64 | terminal emulator and shell: |
| 65 |
|
| 66 | ```bash |
| 67 | #!/usr/bin/env bash |
| 68 | gnome-terminal -- /bin/bash |
| 69 | ``` |
| 70 |
|
| 71 | Using your file browser, give this file permission for user execution and run |
| 72 | it. |
| 73 |
|
| 74 | ## Method 2: Use another user with a functioning login shell |
| 75 |
|
| 76 | This method assumes: |
| 77 |
|
| 78 | - There is a separate user on your system that can be logged into via password |
| 79 | that uses a functioning login shell |
| 80 | - The user is a member of the sudo group |
| 81 |
|
| 82 | Open a virtual console (usually with `<CTRL><ALT><F1..F9>`) and log in as the |
| 83 | separate user. Then, you can take the necessary actions to fix your broken |
| 84 | login shell or other configuration. (On my systems I create a sudoer named |
| 85 | `bash-user` whose sole purpose is to be password-login-able with Bash as its |
| 86 | login shell.) |
| 87 |
|
| 88 | If you don’t have this option, then… |
| 89 |
|
| 90 | ## Method 3: Externally mount the filesystem and forcibly change the default login shell |
| 91 |
|
| 92 | This is the most involved and complicated method, meant to be used as a last |
| 93 | resort if you don’t feel like reimaging your system (or living without a |
| 94 | terminal). You will need to find a way to externally mount the filesystem from |
| 95 | another functioning operating system and change the `/etc/passwd` file |
| 96 | directly. |
| 97 |
|
| 98 | For desktops without any other operating systems installed, my go-to method |
| 99 | looks roughly like this: |
| 100 |
|
| 101 | 1. Create a live USB bootable Linux distribution on a flash drive |
| 102 | (Linux-on-a-stick) |
| 103 | 2. UEFI boot into this Linux-on-a-stick |
| 104 | 3. Force mount the hard drive your Linux system is on, with sufficient |
| 105 | read-write permissions *(Look for external help on this, so as to not break |
| 106 | your filesystem or mess up permissions)* |
| 107 |
|
| 108 | The full details of this method are a bit out of the scope of this article, so |
| 109 | I’ll let you figure them out with the help of Google and StackOverflow. Having |
| 110 | a bootable Linux-on-a-stick is also useful for other reasons, so if you don’t |
| 111 | have one, I do recommend setting one up and using the steps outlined above. |
| 112 |
|
| 113 | Once your filesystem is mounted and you have sufficient read/write permissions, |
| 114 | you can do one of the following: |
| 115 |
|
| 116 | - Directly change `/etc/passwd` to reflect a working login shell for your user |
| 117 | - Through the external operating system, take the necessary actions to fix your |
| 118 | broken login shell (not recommended) |
| 119 |
|
| 120 | After completing this, you should be able to log into your system as normal. |
| 121 |
|
| 122 | # Fixing your custom shell |
| 123 |
|
| 124 | This will vary widely depending on your setup and the shell you’re trying to |
| 125 | fix, so unfortunately I can’t cover that extensively here. In my case, for |
| 126 | fixing `xonsh`, I just had to reinstall it via Python’s package manager with |
| 127 | this command: |
| 128 |
|
| 129 | ```bash |
| 130 | $ sudo python3 -m pip install 'xonsh[full]' |
| 131 | ``` |
| 132 |
|
| 133 | Your process for fixing your broken shell will likely be a similar process of |
| 134 | reinstallation or reconfiguration via `chsh`. |
| 135 |
|