19

I was wondering if there's a way to find out the default shell of the current user within a shell script?

Use case: I am working on a script that sets an alias for a command and this alias is set within a shell script.

!# /bin/bash
alias = 'some command to set the alias'

There's a logic in the script where it tries to find the default shell of the user that executes the script and adds this alias in the respective ~/.bashrc or ~/.zshrc file

But as I am adding a shebang in the front of the script and explicitly asking it to use bash, answers posted here always return bash as expected although I am executing this script on a ZSH terminal.

Is there a way to get the shell type where the script is executed regardless of the shebang set?

I am looking for a solution that works on both Mac and all the linux based bistro.

4
  • @StephenRauch I should have mentioned it earlier, I am looking for a method that works on both Mac and Linux based system. /etc/passwd on Mac does not contain the user information and its only consulted in a single user mode.
    – Spaniard89
    Mar 18 '17 at 15:46
  • What does /etc/passwd have on OSX? I had a quick look online and it appears that the shell is there, just not the username. The user ID's still there though, why don't you use that?
    – terdon
    Mar 18 '17 at 16:03
  • I'd wonder if it's even possible to have an exhaustive list of shells. Or do all shell startup files always conform to .{name_of_shell}rc?
    – jamesqf
    Mar 18 '17 at 18:19
  • Here is an answer to OSX stackoverflow.com/a/16375660/1049542 Nov 20 '20 at 7:06
23

The environment variable, SHELL would always expands to the default login shell of the invoking user (gets the value from /etc/passwd).

For any other given user, you need to do some processing with /etc/passwd, here is a simple awk snippet:

awk -F: -v user="foobar" '$1 == user {print $NF}' /etc/passwd

Replace foobar with the actual username.

If you have ldap (or something similar in place), use getent to get the database instead of directly parsing /etc/passwd:

getent passwd | awk -F: -v user="foobar" '$1 == user {print $NF}'

or cleanest approach, let getent do the parsing (thanks to @Kusalananda):

getent passwd foobar | awk -F: '{print $NF}'
4
  • 4
    getent passwd foobar to skip having to match a particular line.
    – Kusalananda
    Mar 18 '17 at 15:45
  • Thanks for the answer. I should have mentioned it earlier, I am looking for a method that works on both Mac and Linux based system. /etc/passwd on Mac does not contain the user information and its only consulted in a single user mode.
    – Spaniard89
    Mar 18 '17 at 15:46
  • For an explanation of that awk command, see here: unix.stackexchange.com/a/589221/114401 May 27 '20 at 7:54
  • Use getent unless you're never ever going to use a directory for authentication ever. If Unix doesn't have getent you need to restate your question to find the equivalent in your particular Unix distro.
    – Rich
    Aug 5 '20 at 19:15
7
$ finger $USER|grep -oP 'Shell: \K.*'
/bin/mksh
6
  • Thanks it works like a charm! This is the only solution that probably works for both mac and linux based bistro.
    – Spaniard89
    Mar 18 '17 at 15:49
  • 3
    BTW, I edited the command a little bit to make it agnostic to all OS finger $USER | grep 'Shell:*' | cut -f3 -d ":" as the grep options -P is not supported on Mac.
    – Spaniard89
    Mar 18 '17 at 15:53
  • 3
    Note that finger may not be installed on all machines. It's an optional package on RedHat based systems. Mar 18 '17 at 15:56
  • 2
    @Kishorepandey: you can use getent|grep ^$USER:|cut -f: -f7 instead of finger, if finger was not installed by default. Mar 18 '17 at 17:18
  • @Kishorepandey Don't do this. Use the SHELL environment variable if it's present. Looking at the user database will give you a result (the user's login shell) but it might not be the right result (the user's favorite interactive shell) — it depends on the user's configuration. Mar 18 '17 at 23:43
5

Since getent isn't a standard command on MacOS, you may wish to use a lower level getpwuid call that will consult the naming services the machine is configured for. This may require calling out to perl or python, which are pretty common across most Unix-like platforms

eg this will return the shell for the current user:

perl -e '@x=getpwuid($<); print $x[8]'
3

Maybe this:

   grep $USER </etc/passwd | cut -f 7 -d ":"
3
  • This does not improve on any of the already given answers.
    – Kusalananda
    Apr 14 '17 at 14:26
  • This will not work if there are multiple users with works in common; eg if USER=fred then this will match fred, frederick, alfred, alfredo ... Apr 14 '17 at 15:00
  • 1
    @StephenHarris, the solution to that problem is simple: add ^ before the username, to specify "start of line", and : after it, since that's the separator used between fields in /etc/passwd/. Now, you have this answer: grep ^$USER: </etc/passwd | cut -f 7 -d ":", which works perfectly. May 27 '20 at 7:37
2

You can get the user's default shell from the environment like this:

echo $SHELL

But not like this:

echo $0

The latter will just tell you what shell your script is currently using. So you want the first option above.

1
  • 3
    $SHELL is not guaranteed to be the user's default shell either. You want getent or its macOS equivalent.
    – Rich
    Aug 5 '20 at 19:16
1

Short and painless:

getent passwd <USER> | cut -d : -f 7
1

Let me expand on @heemayl's answer, and explain the magical awk code he uses.

1. Just remember the simple stuff:

First off, this:

awk -F: -v user="foobar" '$1 == user {print $NF}' /etc/passwd

while being 100% correct, and the most "right" answer perhaps, is impossible to remember--you'd have to learn awk and then rewrite it logically from scratch each time. What is easy to remember, however, is this: the default shell for a user is the last field on the user's line in the "/etc/passwd" file, where fields are separated by the colon : symbol, and each line in that file begins with a username.

Now, with that knowledge, just think: "ok, I need to find my username line in /etc/passwd". So, do this:

grep $USER /etc/passwd

OR (same effect)

cat /etc/passwd | grep $USER

You'll get something like this:

my_username:x:1001:1001::/home/my_username:/bin/bash

Cool! My default shell is therefore the last field, which means whatever is after the last : symbol. It is /bin/bash. Done.

2. Explanation of this awk command:

awk -F: -v user="foobar" '$1 == user {print $NF}' /etc/passwd

awk is a pattern matching language. You can read the GNU awk, or gawk, manual here, which is a great reference: https://www.gnu.org/software/gawk/manual/gawk.html

  1. /etc/passwd at the end is the file to open and process with awk
  2. -F: says to change the "'F'ield separator" from space (the default) to :.
  3. The -v option sets an awk 'v'ariable you are naming user here, to "foobar"
  4. Now the actual awk program is stored between the single quotes. It's simply $1 == user {print $NF}. Remember: it is its own programming language! It is based on a pattern match or boolean check { action } type flow. It scans down the file one "record" (or line, by default) at a time. $1 is the first field in any given line, and remember, we told it that fields are separated by :, so the first field is my_username. So, $1 == user says "does the first field equal the value stored in the awk variable user"? If so, do the action specified in curly braces { }. The action is to print the value of $NF, where the internal NF variable contains the 'N'umber of 'F'ields for this line. So, the number of fields is 7, since :: contains 1 empty field between those two colons. Therefore, $NF is actually $7, or the value of the 7th field, which is /bin/bash for this user. Behold, the magic of the pattern-matching language, awk.
  5. Done.

3. How to configure a default shell for your user:

What if you want to set or change the default shell for a given user? Use chsh. man chsh says it is used to "change login shell". Here's how to use it:

sudo chsh my_username --shell /path/to/my/shell

Ex: set to use the bash shell (my preferred choice) by default:

sudo chsh my_username --shell /bin/bash

One more way to solve the above problem of finding your default shell, just for fun:

grep ^$USER: /etc/passwd | grep -Eo ':([^:]*)$' | tr -d ':'

Brief description: find the line with the user, find the :/my/shell path at the end, delete the : char from it.

Additional awk learning resources:

  1. See some hello world and syntax test files for awk I wrote here: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/awk
  2. Study git diffn, as an example, here. Note: git diffn is a wrapper I wrote around git diff, to show line numbers.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.