Identify the shell running in my system - bash

Can anyone please tell me what shell has installed in my system?
Because when I am logging into my system using my username it is initially showing bash shell but later it is showing korn shell after doing sudo.
Please see below for details.
-bash-3.2$ pwd
/home/w4x2spxt
-bash-3.2$ echo $SHELL
/bin/bash
-bash-3.2$ su - XXXXXXX
Password:
You have new mail.
The Oracle base remains unchanged with value /apps/oracle
abc0300ab123:/a30/home/XXXXXXX >> echo $SHELL
/bin/ksh

SHELL environment variable gives you your login shell.
check the shell path mentioned(last column) against your username or XXXXXXX(for su) in /etc/passwd like this: grep ^XXXXXXX /etc/passwd.
The shell mentioned in that file will be your default shell when you login or su to that user.
To check all installed shells on your system use this: cat /etc/shells

Your user is using /bin/bash as default shell.
root is using /bin/ksh as its default shell.
The default shell is a user-specific setting, so there is nothing picky in having different ones among users. Just check the last column in /etc/passwd and surprise yourself with a variety of values.
Note by the way that when you do su, you log in as root. If you add the dash and say su - you are loading the root profile, so that you have its environment.

The environment variable SHELL always contains the login shell of the user logged in, defined in /etc/passwd.
If the user changes his/her shell after login by e.g. exec bash (bash), the SHELL will still expand to the login shell.
In your case, the user XXXXXXX has the login shell /bin/ksh, do:
grep '<user_name>' /etc/passwd
to match the results.
To find the current shell:
echo $0
Or
ps -p $$

When you do this:
-bash-3.2$ su - XXXXXXX
you are starting whatever shell is assigned to user XXXXXXX. This is usually a good thing for su -, since that runs their shell as a login process so you get their normal shell startup initialization (profile, *shrc, etc). If you run a different shell from the one their account is set up for, you probably miss out on all their customization.
You can see what shell is associated with an account by looking them up in the password database. This is pretty reliable across different types of systems and authentication schemes:
perl -MUser::pwent -le 'print( (getpwnam "XXXXXXX")->shell || "/bin/sh" )'
You can always run a shell explicitly as the other user if you have one in mind that you want:
su XXXXXXX -c "bash --login"
or
sudo -u XXXXXXX bash --login # if you have sudo privs
To see what shell you're currently running, look at $0:
echo $0
To see what shell you get by default as you, look at $SHELL.

Related

Bash :: SU command removes Variables from SCP Command?

I have a Bash (ver 4.4.20(1)) script running on Ubuntu (ver 18.04.6 LTS) that generates an SCP error. Yet, when I run the offending command on the command line, the same line runs fine.
The script is designed to SCP a file from a remote machine and copy it to /tmp on the local machine. One caveat is that the script must be run as root (yes, I know that's bad, this is a proof-of-concept thing), but root can't do passwordless SCP in my enviroment. User me can so passwordless SCP, so when root runs the script, it must "borrow" me's public SSH key.
Here's my script, slightly abridged for SO:
#!/bin/bash
writeCmd() { printf '%q ' "$#"; printf '\n'; }
printf -v date '%(%Y%m%d)T' -1
user=me
host=10.10.10.100
file=myfile
target_dir=/path/to/dir/$date
# print command to screen so I can see what is being submitted to OS:
writeCmd su - me -c 'scp -C me#$host:/$target_dir/$file.txt /tmp/.'
su - me -c 'scp -C me#$host:/$target_dir/$file.txt /tmp/.'
Output is:
su - me -c scp-Cme#10.10.10.100://.txt/tmp/.
It looks like the ' ' character are not being printed, but for the moment, I'll assume that is a display thing and not the root of the problem. What's more serious is that I don't see my variables in the actual SCP command.
What gives? Why would the variables be ignored? Does the su part of the command interfere somehow? Thank you.
(NOTE: This post has been reedited from its earlier form, if you wondering why the below comments seem off-topic.)
When you run:
writeCmd su - me -c 'scp -C me#$host:/$target_dir/$file.txt /tmp/.'
you'll see that its output is (something equivalent to -- may change version-to-version):
su - me -c scp\ -C\ me#\$host:/\$target_dir/\$file.txt\ /tmp/.
Importantly, none of the variables have been substituted yet (and they're emitted escaped to show that they won't be substituted until after su runs).
This is important, because only variables that have been exported -- becoming environment variables instead of shell variables -- survive a process boundary, such as that caused by the shell starting the external su command, or the one caused by su starting a new and separate shell interpreter as the target user account. Consequently, the new shell started by su doesn't have access to the variables, so it substitutes them with empty values.
Sometimes, you can solve this by exporting your variables: export host target_dir file, and if su passes the environment through that'll suffice. However, that's a pretty big "if": there are compelling security reasons not to pass arbitrary environment variables across a privilege boundary.
The safer way to do this is to build a correctly-escaped command with the variables already substituted:
#!/usr/bin/env bash
# ^^^^- needs to be bash, not sh, to work reliably
cmd=( scp -C "me#$host:/$target_dir/$file.txt" /tmp/. )
printf -v cmd_v '%q ' "${cmd[#]}"
su - me -c "$cmd_v"
Using printf %q is protection against shell injection attacks -- ensuring that a target_dir named /tmp/evil/$(rm -rf ~) doesn't delete your home directory.

.login not called on CentOS Login

as I read the bash shell should call /home/myUser/.login each time myUser logs in.
That is where I want to set and export some variables:
Within /home/myUser/.login:
. /etc/login
... and some user specific variables later.
echo .login done.
Within /etc/login some common variable settings like:
export JBOSS_HOME=/home/ec2-user/sw/wildfly-8.2.0.Final
echo /etc/login done.
None of the both echos is displayed.
But
. /home/myUser/.login
works.
drwx--x--x 6 myUser myUser 4096 Jan 15 18:42 myUser
Because in useradd -m ... the -m is ignored,
and useradd -p hallo ... does not hash the password (but passwd --stdin does),
I wonder if I am the one doing the mistakes ...
welcome to SO!
The bash shell reads from several files during an interactive login session. .login is not one of them.
From the INVOCATION section of the bash man page
When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable. The
--noprofile option may be used when the shell is started to inhibit this behavior.
Hope this answers your question.
From man bash (RHEL 6 and RHEL 7):
~/.bash_profile
The personal initialization file, executed for login shells
~/.bashrc
The individual per-interactive-shell startup file

How to get $HOME directory when switching to a different user in bash?

I need to execute part of a bash script as a different user, and inside that user's $HOME directory. However, I'm not sure how to determine this variable. Switching to that user and calling $HOME does not provide the correct location:
# running script as root, but switching to a different user...
su - $different_user
echo $HOME
# returns /root/ but should be /home/myuser
Update:
It appears that the issue is with the way that I am trying to switch users in my script:
$different_user=deploy
# create user
useradd -m -s /bin/bash $different_user
echo "Current user: `whoami`"
# Current user: root
echo "Switching user to $different_user"
# Switching user to deploy
su - $different_user
echo "Current user: `whoami`"
# Current user: root
echo "Current user: `id`"
# Current user: uid=0(root) gid=0(root) groups=0(root)
sudo su $different_user
# Current user: root
# Current user: uid=0(root) gid=0(root) groups=0(root)
What is the correct way to switch users and execute commands as a different user in a bash script?
Update: Based on this question's title, people seem to come here just looking for a way to find a different user's home directory, without the need to impersonate that user.
In that case, the simplest solution is to use tilde expansion with the username of interest, combined with eval (which is needed, because the username must be given as an unquoted literal in order for tilde expansion to work):
eval echo "~$different_user" # prints $different_user's home dir.
Note: The usual caveats regarding the use of eval apply; in this case, the assumption is that you control the value of $different_user and know it to be a mere username.
By contrast, the remainder of this answer deals with impersonating a user and performing operations in that user's home directory.
Note:
Administrators by default and other users if authorized via the sudoers file can impersonate other users via sudo.
The following is based on the default configuration of sudo - changing its configuration can make it behave differently - see man sudoers.
The basic form of executing a command as another user is:
sudo -H -u someUser someExe [arg1 ...]
# Example:
sudo -H -u root env # print the root user's environment
Note:
If you neglect to specify -H, the impersonating process (the process invoked in the context of the specified user) will report the original user's home directory in $HOME.
The impersonating process will have the same working directory as the invoking process.
The impersonating process performs no shell expansions on string literals passed as arguments, since no shell is involved in the impersonating process (unless someExe happens to be a shell) - expansions by the invoking shell - prior to passing to the impersonating process - can obviously still occur.
Optionally, you can have an impersonating process run as or via a(n impersonating) shell, by prefixing someExe either with -i or -s - not specifying someExe ... creates an interactive shell:
-i creates a login shell for someUser, which implies the following:
someUser's user-specific shell profile, if defined, is loaded.
$HOME points to someUser's home directory, so there's no need for -H (though you may still specify it)
The working directory for the impersonating shell is the someUser's home directory.
-s creates a non-login shell:
no shell profile is loaded (though initialization files for interactive nonlogin shells are; e.g., ~/.bashrc)
Unless you also specify -H, the impersonating process will report the original user's home directory in $HOME.
The impersonating shell will have the same working directory as the invoking process.
Using a shell means that string arguments passed on the command line MAY be subject to shell expansions - see platform-specific differences below - by the impersonating shell (possibly after initial expansion by the invoking shell); compare the following two commands (which use single quotes to prevent premature expansion by the invoking shell):
# Run root's shell profile, change to root's home dir.
sudo -u root -i eval 'echo $SHELL - $USER - $HOME - $PWD'
# Don't run root's shell profile, use current working dir.
# Note the required -H to define $HOME as root`s home dir.
sudo -u root -H -s eval 'echo $SHELL - $USER - $HOME - $PWD'
What shell is invoked is determined by "the SHELL environment variable if it is set or the shell as specified in passwd(5)" (according to man sudo). Note that with -s it is the invoking user's environment that matters, whereas with -i it is the impersonated user's.
Note that there are platform differences regarding shell-related behavior (with -i or -s):
sudo on Linux apparently only accepts an executable or builtin name as the first argument following -s/-i, whereas OSX allows passing an entire shell command line; e.g., OSX accepts sudo -u root -s 'echo $SHELL - $USER - $HOME - $PWD' directly (no need for eval), whereas Linux doesn't (as of sudo 1.8.95p).
Older versions of sudo on Linux do NOT apply shell expansions to arguments passed to a shell; for instance, with sudo 1.8.3p1 (e.g., Ubuntu 12.04), sudo -u root -H -s echo '$HOME' simply echoes the string literal "$HOME" instead of expanding the variable reference in the context of the root user. As of at least sudo 1.8.9p5 (e.g., Ubuntu 14.04) this has been fixed. Therefore, to ensure expansion on Linux even with older sudo versions, pass the the entire command as a single argument to eval; e.g.: sudo -u root -H -s eval 'echo $HOME'. (Although not necessary on OSX, this will work there, too.)
The root user's $SHELL variable contains /bin/sh on OSX 10.9, whereas it is /bin/bash on Ubuntu 12.04.
Whether the impersonating process involves a shell or not, its environment will have the following variables set, reflecting the invoking user and command: SUDO_COMMAND, SUDO_USER, SUDO_UID=, SUDO_GID.
See man sudo and man sudoers for many more subtleties.
Tip of the hat to #DavidW and #Andrew for inspiration.
In BASH, you can find a user's $HOME directory by prefixing the user's login ID with a tilde character. For example:
$ echo ~bob
This will echo out user bob's $HOME directory.
However, you say you want to be able to execute a script as a particular user. To do that, you need to setup sudo. This command allows you to execute particular commands as either a particular user. For example, to execute foo as user bob:
$ sudo -i -ubob -sfoo
This will start up a new shell, and the -i will simulate a login with the user's default environment and shell (which means the foo command will execute from the bob's$HOME` directory.)
Sudo is a bit complex to setup, and you need to be a superuser just to be able to see the shudders file (usually /etc/sudoers). However, this file usually has several examples you can use.
In this file, you can specify the commands you specify who can run a command, as which user, and whether or not that user has to enter their password before executing that command. This is normally the default (because it proves that this is the user and not someone who came by while the user was getting a Coke.) However, when you run a shell script, you usually want to disable this feature.
For the sake of an alternative answer for those searching for a lightweight way to just find a user's home dir...
Rather than messing with su hacks, or bothering with the overhead of launching another bash shell just to find the $HOME environment variable...
Lightweight Simple Homedir Query via Bash
There is a command specifically for this: getent
getent passwd someuser | cut -f6 -d:
getent can do a lot more... just see the man page. The passwd nsswitch database will return the user's entry in /etc/passwd format. Just split it on the colon : to parse out the fields.
It should be installed on most Linux systems (or any system that uses GNU Lib C (RHEL: glibc-common, Deb: libc-bin)
The title of this question is How to get $HOME directory of different user in bash script? and that is what people are coming here from Google to find out.
There is a safe way to do this!
on Linux/BSD/macOS/OSX without sudo or root
user=pi
user_home=$(bash -c "cd ~$(printf %q $USER) && pwd")
NOTE: The reason this is safe is because bash (even versions prior to 4.4) has its own printf function that includes:
%q quote the argument in a way that can be reused as shell input
See: help printf
Compare the how other answers here respond to code injection
# "ls /" is not dangerous so you can try this on your machine
# But, it could just as easily be "sudo rm -rf /*"
$ user="root; ls /"
$ printf "%q" "$user"
root\;\ ls\ /
# This is what you get when you are PROTECTED from code injection
$ user_home=$(bash -c "cd ~$(printf "%q" "$user") && pwd"); echo $user_home
bash: line 0: cd: ~root; ls /: No such file or directory
# This is what you get when you ARE NOT PROTECTED from code injection
$ user_home=$(bash -c "cd ~$user && pwd"); echo $user_home
bin boot dev etc home lib lib64 media mnt ono opt proc root run sbin srv sys tmp usr var /root
$ user_home=$(eval "echo ~$user"); echo $user_home
/root bin boot dev etc home lib lib64 media mnt ono opt proc root run sbin srv sys tmp usr var
on Linux/BSD/macOS/OSX as root
If you are doing this because you are running something as root then you can use the power of sudo:
user=pi
user_home=$(sudo -u $user sh -c 'echo $HOME')
on Linux/BSD (but not modern macOS/OSX) without sudo or root
If not, the you can get it from /etc/passwd. There are already lots of examples of using eval and getent, so I'll give another option:
user=pi
user_home=$(awk -v u="$user" -v FS=':' '$1==u {print $6}' /etc/passwd)
I would really only use that one if I had a bash script with lots of other awk oneliners and no uses of cut. While many people like to "code golf" to use the fewest characters to accomplish a task, I favor "tool golf" because using fewer tools gives your script a smaller "compatibility footprint". Also, it's less man pages for your coworker or future-self to have to read to make sense of it.
You want the -u option for sudo in this case. From the man page:
The -u (user) option causes sudo to run the specified command as a user other than root.
If you don't need to actually run it as them, you could move to their home directory with ~<user>. As in, to move into my home directory you would use cd ~chooban.
So you want to:
execute part of a bash script as a different user
change to that user's $HOME directory
Inspired by this answer, here's the adapted version of your script:
#!/usr/bin/env bash
different_user=deploy
useradd -m -s /bin/bash "$different_user"
echo "Current user: $(whoami)"
echo "Current directory: $(pwd)"
echo
echo "Switching user to $different_user"
sudo -u "$different_user" -i /bin/bash - <<-'EOF'
echo "Current user: $(id)"
echo "Current directory: $(pwd)"
EOF
echo
echo "Switched back to $(whoami)"
different_user_home="$(eval echo ~"$different_user")"
echo "$different_user home directory: $different_user_home"
When you run it, you should get the following:
Current user: root
Current directory: /root
Switching user to deploy
Current user: uid=1003(deploy) gid=1003(deploy) groups=1003(deploy)
Current directory: /home/deploy
Switched back to root
deploy home directory: /home/deploy
This works in Linux. Not sure how it behaves in other *nixes.
getent passwd "${OTHER_USER}"|cut -d\: -f 6
I was also looking for this, but didn't want to impersonate a user to simply acquire a path!
user_path=$(grep $username /etc/passwd|cut -f6 -d":");
Now in your script, you can refer to $user_path in most cases would be /home/username
Assumes: You have previously set $username with the value of the intended users username.
Source: http://www.unix.com/shell-programming-and-scripting/171782-cut-fields-etc-passwd-file-into-variables.html
Quick and dirty, and store it in a variable:
USER=somebody
USER_HOME="$(echo -n $(bash -c "cd ~${USER} && pwd"))"
I was struggling with this question because I was looking for a way to do this in a bash script for OS X, hence /etc/passwd was out of the question, and my script was meant to be executed as root, therefore making the solutions invoking eval or bash -c dangerous as they allowed code injection into the variable specifying the username.
Here is what I found. It's simple and doesn't put a variable inside a subshell. However it does require the script to be ran by root as it sudos into the specified user account.
Presuming that $SOMEUSER contains a valid username:
echo "$(sudo -H -u "$SOMEUSER" -s -- "cd ~ && pwd")"
I hope this helps somebody!
If the user doesn't exist, getent will return an error.
Here's a small shell function that doesn't ignore the exit code of getent:
get_home() {
local result; result="$(getent passwd "$1")" || return
echo $result | cut -d : -f 6
}
Here's a usage example:
da_home="$(get_home missing_user)" || {
echo 'User does NOT exist!'; exit 1
}
# Now do something with $da_home
echo "Home directory is: '$da_home'"
The output of getent passwd username can be parsed with a Bash regular expression
OTHER_HOME="$(
[[ "$(
getent \
passwd \
"${OTHER_USER}"
)" =~ ([^:]*:){5}([^:]+) ]] \
&& echo "${BASH_REMATCH[2]}"
)"
If you have sudo active, just do:
sudo su - admin -c "echo \$HOME"
NOTE: replace admin for the user you want to get the home directory

How to get the default shell

We can run something like chsh -s /usr/local/bin/zsh to set a new default shell. Is there a command we can run to know what that shell is?
I don’t mean having a terminal open and running a command to know which shell we’re in. I mean like in the example above, if I’m in a terminal with /bin/bash open, what should I run to get /usr/local/bin/zsh if it’s the current default shell?
You can use the following command:
echo $SHELL
For macOS:
dscl . -read /Users/username UserShell
For the current macOS user:
dscl . -read ~/ UserShell
To parse the path inline using sed:
dscl . -read ~/ UserShell | sed 's/UserShell: //'
Using $SHELL will report the current login shell, not the default login shell. In certain cases, these are not the same. For example, when working in an IDE such as Visual Studio Code which opens an integrated terminal without consulting the default shell.
In addition, as pointed out by Martin C. Martin, $SHELL is a constant that will not change after chsh changes the default login shell.
You can grep in the /etc/passwd file for current username, and use cut to extract the appropriate column of information:
grep ^$(id -un): /etc/passwd | cut -d : -f 7-
$(id -un) is a safer than $USER to get user name. Using ^ in front of user name and : after makes sure you don't get a false match if your user name is a sub section of someone else user name.
$SHELL can also be used, as suggested. However it won't work if chsh was used in current shell, as the variable is not updated. Also the variable is not protected against being changed, so it can theoretically be set to something completely different.
Update to attempt an OS X compatible solution. Probably not optimal regexp:
grep ^.*:.*:$(id -u): /etc/passwd | cut -d : -f 7-
This is based on user id's. If the whole user entry is missing, not only user name, then osx must store this somewhere else.
If you want to get the default shell of a user, you could grep file /etc/passwd. like:
grep "$USER" /etc/passwd
# kent:x:1000:1000::/home/kent:/bin/zsh
telling me that the current user (kent) has the default shell /bin/zsh.
If you just want to catch the shell part:
awk -F: -v u="$USER" 'u==$1&&$0=$NF' /etc/passwd
# /bin/zsh
If you want to get the default shell of other user, just replace the $USER part.
In OS X, using the command env | grep -i 'SHELL' produces an output such as: SHELL=/bin/sh
(as root, however regular users tend to have /bin/bash as default shell) with a little parsing, the path the shell (and thus the shell itself) could be easily identified and extracted from there..

Changing to root user inside shell script

I have a shell script which needs non-root user account to run certain commands and then change the user to root to run the rest of the script. I am using SUSE11.
I have used expect to automate the password prompt. But when I use
spawn su -
and the command gets executed, the prompt comes back with root and the rest of the script does not execute.
Eg.
< non-root commands>
spawn su -
<root commands>
But after su - the prompt returns back with user as root.
How to execute the remaining of the script.
The sudo -S option does not help as it does not run sudo -S ifconfig command which I need to find the IP address of the machine.
I have already gone through these links but could not find a solution:
Change script directory to user's homedir in a shell script
Changing unix user in a shell script
sudo will work here but you need to change your script a little bit:
$ cat 1.sh
id
sudo -s <<EOF
echo Now i am root
id
echo "yes!"
EOF
$ bash 1.sh
uid=1000(igor) gid=1000(igor) groups=1000(igor),29(audio),44(video),124(fuse)
Now i am root
uid=0(root) gid=0(root) groups=0(root)
yes!
You need to run your command in <<EOF block and give the block to sudo.
If you want, you can use su, of course. But you need to run it using expect/pexpect that will enter password for you.
But even in case you could manage to enter the password automatically (or switch it off) this construction would not work:
user-command
su
root-command
In this case root-command will be executed with user, not with root privileges, because it will be executed after su will be finished (su opens a new shell, not changes uid of the current shell). You can use the same trick here of course:
su -c 'sh -s' <<EOF
# list of root commands
EOF
But now you have the same as with sudo.
There is an easy way to do it without a second script. Just put this at the start of your file:
if [ "$(whoami)" != "root" ]
then
sudo su -s "$0"
exit
fi
Then it will automatically run itself as root. Of course, this assumes that you can sudo su without having to provide a password - but that's out of scope of this answer; see one of the other questions about using sudo in shell scripts for how to do that.
Short version: create a block to enclose all commands to be run as root.
For example, I created a script to run a command from a root subdirectory, the segment goes like this:
sudo su - <<EOF
cd rootSubFolder/subfolder
./commandtoRun
EOF
Also, note that if you are changing to "root" user inside a shell script like below one, few Linux utilities like awk for data extraction or defining even a simple shell variable etc will behave weirdly.
To resolve this simply quote the whole document by using <<'EOF' in place of EOF.
sudo -i <<'EOF'
ls
echo "I am root now"
EOF
The easiest way to do that would be to create a least two scripts.
The first one should call the second one with root privileges. So every command you execute in the second script would be executed as root.
For example:
runasroot.sh
sudo su-c'./scriptname.sh'
scriptname.sh
apt-get install mysql-server-5.5
or whatever you need.

Resources