How do I get the current user's username in Bash? - bash

How do I get the current user's username in Bash? Do I use whoami?

On the command line, enter
whoami
or
echo "$USER"

An alternative to whoami is id -u -n.
id -u will return the user id (e.g. 0 for root).

Use the standard Unix/Linux/BSD/MacOS command logname to retrieve the logged in user. This ignores the environment as well as sudo, as these are unreliable reporters. It will always print the logged in user's name and then exit. This command has been around since about 1981.
My-Mac:~ devin$ logname
devin
My-Mac:~ devin$ sudo logname
Password:
devin
My-Mac:~ devin$ sudo su -
My-Mac:~ root# logname
devin
My-Mac:~ root# echo $USER
root

A hack the I've used on Solaris 9 and Linux and which works fine for both of them:
ps -o user= -p $$ | awk '{print $1}'
This snippet prints the name of the user with the current EUID.
NOTE: you need Bash as the interpreter here.
On Solaris you have problems with methods, described above:
id does not accept the -u and -n parameters (so you will have to parse the output)
whoami does not exist (by default)
who am I prints owner of current terminal (ignores EUID)
$USER variable is set correctly only after reading profile files (for example, /etc/profile)

Two commands:
id prints the user id along with the groups.
Format: uid=usernumber(username) ...
whoami gives the current user name

When root (sudo) permissions are required, which is usually 90%+ when using scripts, the methods in previous answers always give you root as the answer.
To get the current "logged in" user is just as simple, but it requires accessing different variables: $SUDO_UID and $SUDO_USER.
They can be echoed:
echo $SUDO_UID
echo $SUDO_USER
Or assigned, for example:
myuid=$SUDO_UID
myuname=$SUDO_USER

In Solaris OS I used this command:
$ who am i # Remember to use it with space.
On Linux- Someone already answered this in comments.
$ whoami # Without space

REALUSER="${SUDO_USER:-${USER}}"
...gets you the regular user (if non-sudo) → or ← the regular user behind the current sudo call.

The current user's username can be gotten in pure Bash with the ${parameter#operator} parameter expansion (introduced in Bash 4.4):
$ : \\u
$ printf '%s\n' "${_#P}"
The : built-in (synonym of true) is used instead of a temporary variable by setting the last argument, which is stored in $_. We then expand it (\u) as if it were a prompt string with the P operator.
This is better than using $USER, as $USER is just a regular environmental variable; it can be modified, unset, etc. Even if it isn't intentionally tampered with, a common case where it's still incorrect is when the user is switched without starting a login shell (su's default).

For Bash, KornShell (ksh), sh, etc. Many of your questions are quickly answered by either:
man [function]
to get the documentation for the system you are using or usually more conveniently:
google "man function"
This may give different results for some things where Linux and Unix have modest differences.
For this question, just enter "whoami" in your shell.
To script it:
myvar=$(whoami)

On most Linux systems, simply typing whoami on the command line provides the user ID.
However, on Solaris, you may have to determine the user ID, by determining the UID of the user logged-in through the command below.
echo $UID
Once the UID is known, find the user by matching the UID against the /etc/passwd file.
cat /etc/passwd | cut -d":" -f1,3

This is a small simple example bash script I made for pushing my code to my personal gitlab, it spits out my current username in my commit message.
# !/bin/sh
# This example script is for pushing my code to gitlab
echo Starting Push for user : $(whoami), Please enter Commit Message
below:
read varMessage
# this prompts the user for an input messsage , then saves the result in
# a variable
git add .
git commit -m "$(whoami): $varMessage"
git push -u "url_of_project" master
Resultant commit message in my personal gitlab looks like this:-
walexia : updated Matplotib example

All,
From what I'm seeing here all answers are wrong, especially if you entered the sudo mode, with all returning 'root' instead of the logged in user. The answer is in using 'who' and finding eh 'tty1' user and extracting that. Thw "w" command works the same and var=$SUDO_USER gets the real logged in user.
Cheers!
TBNK

Get the current task's user_struct
#define get_current_user() \
({ \
struct user_struct *__u; \
const struct cred *__cred; \
__cred = current_cred(); \
__u = get_uid(__cred->user); \
__u; \
})

Related

How to run command as another user

I have a shell script that makes a few calls to Asterisk at some point and shows some output. Calling Asterisk is the first thing I have tried that seems not to work. I determined the user I setup to run the script didn't have the permissions to run Asterisk, so I looked at ways to run it as root which would get around that (the only other user on the system).
I tried using su with no luck. For the past two hours, I've been messing with sudo and sudoers and not been able to get it working.
For example, here is some code called in my script, run by the user com:
printf "\n"
calls=`sudo "asterisk -rx 'core show channels'" | grep "active call"`
lastinboundcaller=`cat /var/log/asterisk/lastcaller.txt`
printf '%s\n' "Current Call Count: $calls"
printf '%s\n' "Last Inbound Caller: $lastinboundcaller"
Output:
[sudo] password for com:
sudo: asterisk -rx 'core show channels': command not found
Current Call Count:
Last Inbound Caller: Unknown
There are two problems here,
It's prompting for a password. Why it's prompting for the current user's password rather than the root password, I have no idea, but it shouldn't prompt for any password at all.
The Asterisk command asterisk -rx "command" is still not working — in other words, it's still failing to run the Asterisk shell, though it should have permission.
I tried updating my sudoers file and creating a new file in /etc/sudoers.d titled asterisk as well and putting my command in there.
My latest modification to that file was:
com ALL = (ALL:ALL) NOPASSWD: /usr/sbin/asterisk
Before that, I tried:
com ALL = (root) NOPASSWD: /usr/sbin/asterisk
My understanding is this should allow the user com to execute asterisk as sudo without a password. Clearly, something is not working.
I have followed the answers to numerous similar SO posts, like:
Use sudo without password INSIDE a script
https://unix.stackexchange.com/questions/18877/what-is-the-proper-sudoers-syntax-to-add-a-user
Unfortunately, despite following all the answers I've been able to find on this issue, none have worked for me.
Can anyone point me in the right direction here or suggest an alternative? I already consulted a Linux expert and this seems to be the right approach. This is all super easy to do in Windows and I'm surprised it's all this convoluted in Linux.
Don't quote the argument to sudo. It expects the first argument to be the name of the command, so it thinks the whole command line is the program name.
It should be
calls=`sudo asterisk -rx 'core show channels' | grep "active call"`
Why it's prompting for the current user's password rather than the root password, I have no idea, but it shouldn't prompt for any password at all.
That's how sudo works. It prompts for the current user's password, and checks /etc/sudoers to see if they're allowed to run the command. You're thinking of su, which prompts for the root password.

Pass password to sudo for command that expects input

I am trying to create a Shell script and (to avoid typing, furthermore ignoring security related issues for now) want to directly pass the password to the "sudo" command, e.g.,
pword="mypassword"
echo $pword | sudo -S whoami
This works just fine. But now when the command itself expects an input, this method seems to fail, e.g.,
echo $pword | sudo -S cat<<<"Hello"
This would lead to an 'incorrect password' error. Currently, my solution is to run a "dummy command" like in example one first, and use the fact that for the second command the system does not prompt for a password again. However, does anyone know a better solution to get it to work?
You can defer the activation of the "here document" (the <<< construct) by doing something like this:
echo $pw | sudo -S sh -c ' cat <<<"Hello" '
A better solution is to use sudo -A instead of sudo -S, after first defining a $SUDO_ASKPASS environment variable to refer to a program that will emit your password. Then you won't have to worry about competing for stdin with the rest of the command line. You should create that askpass program (it can be a shell script) to be readable, writable and executable only by yourself so that your password will be securely hidden inside the program.
The -v flag of sudo is also useful if you have just entered your password for the SSH connection, -v updates the cache and doesn't ask for a password again:
sudo -v -u UserName && bash -c 'cat <<<"Hello"'

securely passing password through bash

I am building a bash script for my work to make initial setup and windows-domain join for our Ubuntu machines easy enough for someone who knows nothing about Linux can do it. I have found a lot of people that say that you shouldn't pass passwords through a script but to be efficient, I have to. The script prompts for info and credentials in the beginning and it needs to be able to be left to do it's job without interaction. I can't have it visible through ps when I pass it and I can't have it stored as an unsecured variable. Any suggestions?
If you really must do this, you can read the credentials into variables with read -s early in the script and then pass those values to the prompts. For example:
read -p "Enter your username: " username
read -sp "Enter your password: " password
echo
I included the blank echo because the -s option for read prevents the user's typing from appearing in the terminal, including the new line usually created after a user presses Enter when answering a prompt.
You can then use the $username and $password variables for the rest of your script and the credentials will not have to be stored outside of memory, meaning they will be lost/destroyed after the script completes.
However, note that any programs or utilities which take the credentials as command-line arguments will display those to other users on the machine running the script. For example, if I were to run a MySQL query using this method, I could do:
mysql -u "${username}" -p"${password}" -e "SHOW DATABASES;"
Other users on the machine could see the credentials while that was running with something like ps:
ps -ef | grep mysql
...
watrudoin 29512 29443 0 12:57 pts/4 00:00:00 mysql -u MyUserName -phunter2 -e SHOW DATABASES
You just need to be aware that what you are doing is not necessarily secure, but it seems that you already are.

Switching users in a shell script

OS: Ubunut 14.04
I have a shell script, and I would like to run a portion of the script as a different user. I tried adding the following to my script:
echo 'user_password' | su user_name
cd ~
ls -l
But I am getting the following message:
su: must be run from a terminal
Any ideas?
Keep in mind that it is a bad security practice to store a user's password in plaintext.
If you really want to read the password from STDIN, you can use the -S option of sudo, which doesn't seem to have a counterpart in the su command.
For a better solution, that doesn't involve storing the password in plaintext, see the answers on this askubuntu thread.

SMB Client Commands Through Shell Script

I have a shell script, which I am using to access the SMB Client:
#!/bin/bash
cd /home/username
smbclient //link/to/server$ password -W domain -U username
recurse
prompt
mput baclupfiles
exit
Right now, the script runs, accesses the server, and then asks for a manual input of the commands.
Can someone show me how to get the commands recurse, prompt, mput baclupfiles and exit commands to be run by the shell script please?
I worked out a solution to this, and sharing for future references.
#!/bin/bash
cd /home/username
smbclient //link/to/server$ password -W domain -U username << SMBCLIENTCOMMANDS
recurse
prompt
mput backupfiles
exit
SMBCLIENTCOMMANDS
This will enter the commands between the two SMBCLIENTCOMMANDS statements into the smb terminal.
smbclient accepts the -c flag for this purpose.
-c|--command command string
command string is a semicolon-separated list of commands to be executed instead of
prompting from stdin.
-N is implied by -c.
This is particularly useful in scripts and for printing stdin to the server, e.g.
-c 'print -'.
For instance, you might run
$ smbclient -N \\\\Remote\\archive -c 'put /results/test-20170504.xz test-20170504.xz'
smbclient disconnects when it is finished executing the commands.
smbclient //link/to/server$ password -W domain -U username -c "recurse;prompt;mput backupfiles"
I would comment to Calchas's answer which is the correct approach-but did not directly answer OP's question-but I am new and don't have the reputation to comment.
Note that the -c listed above is semicolon separated list of commands (as documented in other answers), thus adding recurse and prompt enables the mput to copy without prompting.
You may also consider using the -A flag to use a file (or a command that decrypts a file to pass to -A) to fully automate this script
smbclient //link/to/server$ password -A ~/.smbcred -c "recurse;prompt;mput backupfiles"
Where the file format is:
username = <username>
password = <password>
domain = <domain>
workgroup = <workgroup>
workgroup is optional, as is domain, but usually needed if not using a domain\username formatted username.
I suspect this post is WAY too late to be useful to this particular need, but maybe useful to other searchers, since this thread lead me to the more elegant answer through -c and semicolons.
I would take a different approach using autofs with smb. Then you can eliminate the smbclient/ftp like approach and refactor your shell script to use other functions like rsync to move your files around. This way your credentials aren't stored in the script itself as well. You can bury them somewhere on your fs and make it read only by root an no one else.

Resources