I created the following BASH script that works perfectly for getting a password from the user:
while [ -z "$PASSWORD" ]
do
echo "Please enter a password:"
read -s PASSWORD1
echo "Please re-enter the password to confirm:"
read -s PASSWORD2
if [ "$PASSWORD1" = "$PASSWORD2" ]; then
PASSWORD=$PASSWORD1
else
# Output error message in red
red='\033[0;31m'
NC='\033[0m' # No Color
echo ""
echo -e "${red}Passwords did not match!${NC}"
fi
done
# This is just here to prove script works
echo "password is: $PASSWORD"
However, if I place it in a function, it stops working:
function getPasswordFromUser()
{
while [ -z "$PASSWORD" ]
do
echo "Please enter a password:"
read -s PASSWORD1
echo "Please re-enter the password to confirm:"
read -s PASSWORD2
if [ "$PASSWORD1" = "$PASSWORD2" ]; then
PASSWORD=$PASSWORD1
else
# Output error message in red
red='\033[0;31m'
NC='\033[0m' # No Color
echo ""
echo -e "${red}Passwords did not match!${NC}"
fi
done
echo $PASSWORD
}
PASSWORD=$(getPasswordFromUser)
# This is just here to check if script worked
echo "got password $PASSWORD"
If I change the call to the function from PASSWORD=$(getPasswordFromUser) to: getPasswordFromUser; then the method starts "working" but the password is output to the screen, and I haven't captured it.
Is there a way to update this BASH script so that I can call a function to get a password from the user without the password ever being displayed in the terminal?
In case it matters, this is for Debian/Ubuntu.
If you call the function like myvar=$(myfunction) it will catch the first echo statement.
What you can do, instead, is to define a variable within the function and then access it. There is no scope in bash, so you will be able to access it once the function has been executed.
See an example on each one of them:
$ cat a
#!/bin/bash
function myf()
{
echo "heeeiiii"
echo "hellO"
}
function myf2()
{
echo "lets define var MYTEST"
MYTEST="this is my test"
}
r=$(myf)
echo "this is myf: $r"
echo "MYTEST=$MYTEST"
myf2
echo "MYTEST=$MYTEST"
Execution:
$ ./a
this is myf: heeeiiii
hellO
MYTEST=
lets define var MYTEST
MYTEST=this is my test
Most of the output in your function should be written to standard error, not standard output.
getPasswordFromUser()
{
while [ -z "$PASSWORD" ]
do
echo "Please enter a password:" >&2
read -s PASSWORD1
echo "Please re-enter the password to confirm:" >&2
read -s PASSWORD2
if [ "$PASSWORD1" = "$PASSWORD2" ]; then
PASSWORD=$PASSWORD1
else
# Output error message in red
red='\033[0;31m'
NC='\033[0m' # No Color
echo -e "\n${red}Passwords did not match!${NC}" >&2
fi
done
echo "$PASSWORD"
}
Also, be sure to quote $PASSWORD in the final line; someone may use multiple runs of whitespace or shell glob characters in their password!
Your first attempt is correct:
~$ PASSWORD=$(getPasswordFromUser)
~$ echo $PASSWORD
Please enter a password: Please re-enter the password to confirm: a
You just don't see the "Please enter a password" because it is captured by the $(..).
You have several possibilities:
use a global variable
use different descriptor
have the function take a variable as the first arg and modify the variable with the string you want to return.
Some examples can be found in how to return a string value from a bash function, the Advanced Bash-Scripting Guide, or the linux journal.
Related
I'm trying to create a bash script that asks for password when you try to see the password file, but I'm stucked. This is my code:
#!/bin/bash
# Read Password
echo -n Password:
read -s PASSWORD
passwords() {
echo "
PASSWORDS
"
}
if [ "$PASSWORD"="root" ]; then
passwords
exit
else
echo "Wrong password"
exit
fi
I've tried a lot of things, for example if [ "$PASSWORD"!="root" ] instead of else but none of them worked.
Here is a shorter version:
#!/bin/bash
passwords(){
echo "PASSWORDS"
}
## Read Password
read -p "Enter password: " -s PASSWORD
desired_password="root"
[ "$PASSWORD" == "$desired_password" ] && passwords || echo "Wrong password"
As #vdavid said, you can add a space around the equal sign or even better, as you have bash shell, it is recommended to use double-bracket for your if statement. Check this: Is there any difference between '=' and '==' operators in bash or sh
Also you can add:
printf "/n" so your script will behave like a typical Linux prompt for password - information will output in new line
non-zero exit code in case of wrong password (exit 1)
Basically, after those improvements code looks like this:
#!/bin/bash
# Read Password
echo -n Password:
read -s PASSWORD
printf "\n"
passwords() {
echo "PASSWORDS"
}
if [[ "$PASSWORD" == "root" ]]; then
passwords
exit 0
else
echo "Wrong password"
exit 1
fi
Note that I used "==" instead of "=", but for double-bracket they both do the same job.
I have a bash script that prompts the user for different information based on what they're trying to do. The prompts are usually done with read -p. Usually it works just fine, the user sees what is being asked, enters what they need to enter, and everything does what it needs to do.
See the following (sanitized) snippet of a function in the script:
#!/bin/bash
function_name() {
if [ "$this_value" == "default" ];then
echo "Value set to default."
read -p "Enter desired value here: " desired_value
desired_value=${desired_value^^}
if [ "${#desired_value}" != 3 ] ;then
echo "$desired_value is an invalid entry."
exit 1
fi
if [ "$desired_value" != "$(some command that returns something to compare against)" ];then
echo "$desired_value is an invalid entry."
exit 1
fi
read -p "You entered $desired_value. Is this correct? [y/N] " reply
reply=${reply,,}
case "$reply" in
y|yes)
$some command that does what I want it to do
;;
*)
echo "User did not enter yes"
exit 1
;;
esac
fi
}
Usually the Enter desired value here and is this correct? lines appear just fine. But in a few instances I've seen, for some reason the read prompt is just blank. A user will see the following:
./script.bash
##unrelated script stuff
##unrelated script stuff
Value set to default.
user_entered_value_here
User did not enter yes. Exiting.
This is a real example that just happened that finally made me come here to ask what is going on (and I modified appropriately to make it an SO post).
What's happening is these two blank lines appear instead of the read -p text. For the first one, the user entered user_entered_value_here because they already know what is supposed to be entered there even without the read prompt. The second one, the Y/N prompt, they don't know, so they see it apparently hanging, and hit Enter instead of y, causing it to trigger the * case option.
I don't understand why the read -p text is not appearing, and especially why it's appearing for most users but not all users. I suspect there's some kind of environmental setting that causes this, but for the life of me I can't figure out what. This is being run only on RHEL 6.2, under bash 4.1.2.
I looked at the man of bash to catch some kind of detail about the read built-in. It is specified that -p option displays the "prompt on standard error, without a trailing newline, before attempting to read any input. The prompt is displayed only if input is coming from a terminal".
Let's consider the simple script input.sh:
#!/bin/bash
read -p "Prompt : " value
echo The user entered: "$value"
Example of execution:
$ ./input.sh
Prompt : foo
The user entered: foo
If stderr is redirected:
$ ./input.sh 2>/dev/null
foo
The user entered: foo
If the input is a pipe
$ echo foo | ./input.sh
The user entered: foo
If the input is a heredoc
$ ./input.sh <<EOF
> foo
> EOF
The user entered: foo
Rewrote your script with shell agnostic grammar and fixed some errors like comparing the string length with a string comparator != = rather than a numerical comparator -ne -eq:
#!/usr/bin/env sh
this_value=default
toupper() {
echo "$1" | tr '[:lower:]' '[:upper:]'
}
function_name() {
if [ "$this_value" = "default" ]; then
echo "Value set to default."
printf "Enter desired value here: "
read -r desired_value
desired_value=$(toupper "$desired_value")
if [ "${#desired_value}" -ne 3 ]; then
printf '%s is an invalid entry.\n' "$desired_value"
exit 1
fi
if [ "$desired_value" != "$(
echo ABC
: some command that returns something to compare against
)" ]; then
echo "$desired_value is an invalid entry."
exit 1
fi
printf 'You entered %s. Is this correct? [y/N] ' "$desired_value"
read -r reply
reply=$(toupper "$reply")
case $reply in
'y' | 'yes')
: "Some command that does what I want it to do"
;;
*)
echo "User did not enter yes"
exit 1
;;
esac
fi
}
function_name
I have the following script:
#!/bin/bash
#
# Example script for validating SVN credentials.
var_svn_user_name=
var_svn_password=
function get_svn_credentials()
{
# First, get the credentials from the user
read -r -p "Please enter SVN User Name: " var_svn_user_name
echo -n "Please enter SVN Password: "
read -r -s var_svn_password
echo ""
echo "----------------"
echo "The SVN User Name is: ${var_svn_user_name}"
echo "The SVN User Password is: ${var_svn_password}"
# Next, validate provided credentials
echo -n "Validating credentials... "
#var_ret=$(svn list --username "${var_svn_user_name}" --password \
# "${var_svn_password}" ${var_url} ${var_cfg} ${var_opt}=${var_val} \
# --no-auth-cache --non-interactive 2>&1 | grep "Authentication failed")
if [[ $var_ret == "" ]]
then
echo 'Success'
else
echo 'Failed'
fi
}
function main()
{
# EXAMPLE Call #1
#result=$(get_svn_credentials) # FAILURE
# EXAMPLE Call #2
get_svn_credentials # SUCCESS
echo "Return value is: $result"
if [[ $var_ret == "Success" ]]
then
echo "SVN User Name and Password was validated."
else
echo "SVN User Name and Password was NOT validated."
fi
}
main "$#"
Why is it that when I comment out Example 2 and uncomment Example 1, the echoing of password does not get displayed until read executes?
I am trying to figure out how to get the return statement to work like a C function style return statement.
Would anyone be able to help with this?
You are writing your prompt to standard output, which is captured by the command substitution. Write it to standard error instead (like read -p does).
function get_svn_credentials()
{
# First, get the credentials from the user
read -r -p "Please enter SVN User Name: " var_svn_user_name
echo -n "Please enter SVN Password: " >&2
read -r -s var_svn_password
{
echo ""
echo "----------------"
echo "The SVN User Name is: ${var_svn_user_name}"
echo "The SVN User Password is: ${var_svn_password}"
} >&2
# Next, validate provided credentials
echo -n "Validating credentials... "
#var_ret=$(svn list --username "${var_svn_user_name}" --password \
# "${var_svn_password}" ${var_url} ${var_cfg} ${var_opt}=${var_val} \
# --no-auth-cache --non-interactive 2>&1 | grep "Authentication failed")
if [[ $var_ret == "" ]]
then
echo 'Success'
else
echo 'Failed'
fi
}
That said, don't rely on the output to determine if it succeeded or not; just use the exit status.
get_svn_credentials () {
local user_name password
# First, get the credentials from the user
read -r -p "Please enter SVN User Name: " user_name
read -r -p "Please enter SVN Password: " -s password
{
echo ""
echo "----------------"
echo "The SVN User Name is: ${user_name}"
echo "The SVN User Password is: ${password}"
} >&2
# Next, validate provided credentials
# Let the exit status of grep -q be the exit status
# of the function
printf '%s\n' "Validating credentials... " >&2
svn list --username "${user_name}" \
--password "${password}" \
"${var_url}" ${var_cfg} "${var_opt}=${var_val}" \
--no-auth-cache --non-interactive 2>&1 |
grep -q "Authentication failed"
}
main () {
if get_svn_credentials
then
echo "SVN User Name and Password was validated."
else
echo "SVN User Name and Password was NOT validated."
fi
}
main
(Note: you should probably be quoting $var_cfg, but it's possible it is actually a list of options. In that case, you should be using an array instead, but as it's impossible to tell from this code alone, I've left it unquoted.)
UPDATE: I am really frustrated at this point. I've tried moving the expect code to its own file and calling it from the bash script.
...
if [[ "$okay" == "OK" ]]
then
echo "PASSWORD ACCEPTED"
echo "Modifying User Passwords..."
COUNTER=0
while [ $COUNTER -lt $num ]; do
let index=COUNTER+1
tmp=user_$index
echo "Changing Password for " ${!tmp}
tmp2=$(${!tmp})
echo $tmp2
sh ./input.sh ${current_user} ${pass} ${password} ${tmp2}
let COUNTER=COUNTER+1
done
...
input.sh
expect -f
#------------------------------------------------------
set current_user [lindex $argv 0]
set pass [lindex $argv 1]
set password [lindex $argv 2]
set tmp2 [lindex $argv 3]
echo "EXPECT SCRIPT RUNNING"
sudo passwd ${!tmp2}
expect -exact "[sudo] password for $current_user: "
send "$pass\r"
expect -exact "New password: "
send "$password\r"
I would greatly, greatly appreciate it if someone could help me out.
I am writing a script that will allow a Linux admin to quickly change passwords of its users.
#!/usr/bin/expect
# Check password for strength
# ----------------------------------------------
read -p "What's your username?" current_user
read -p "What's the root password?" pass
read -p "How many users?" num
COUNTER=0
while [ $COUNTER -lt $num ]; do
let index=COUNTER+1
read -p "Enter username$index : " user_$index
let COUNTER=COUNTER+1
done
read -p "Enter password : " password
echo
echo "Tesing password strength..."
echo
result="$(cracklib-check <<<"$password")"
okay="$(awk -F': ' '{ print $2}' <<<"$result")"
if [[ "$okay" == "OK" ]]
then
echo "PASSWORD ACCEPTED"
echo "Modifying User Passwords..."
COUNTER=0
while [ $COUNTER -lt $num ]; do
let index=COUNTER+1
tmp=user_$index
echo "Changing Password for " ${!tmp}
echo ${!tmp}
sudo passwd ${!tmp}
expect -exact "[sudo] password for $current_user: "
send "$pass\r"
expect -exact "New password: "
send "$password\r"
let COUNTER=COUNTER+1
done
#echo "$user:$password" | usr/sbin/chpasswd
else
echo "Your password was rejected - $result"
echo "Try again."
fi
However, the expect portion, which would automate the inputting of passwords, is not highlighted in my editor and does not work. I keep getting prompts to manually enter text. This is especially surprising since the script is sourcing expect, not bash. I've been trying to fix this for the past 2 hours. Can anyone please lend me a hand?
I see some issues in your code. At first, you have tried adding #!/usr/bin/expect in the code, which should throw you an error about the read command as,
wrong # args: should be "read channelId ?numChars?" or "read ?-nonewline? channelId"
while executing
"read -p "What's your username?" current_user"
The reason is simply because the script will be treated as Expect script and it is not following it's syntax for read. I wonder how it worked for you. :)
When it is called as shell script, in that it should be enclosed withing expect -c not simply with expect -f
When expect -c is enclosed with single quotes, it won't allow bash substitutions. So, I am going to use double quotes. (but, it we have to escape the Expect's double quotes with backslashes.)
admin="dinesh"
admin_pwd="root"
user="satheesh"
user_pwd="Hello#12E"
OUTPUT=$(expect -c "
# To suppress any other form of output generated by spawned process
log_user 0
spawn sudo passwd $user
expect {
timeout { send_user \"Timeout happened\n\";exit 0}
\"Sorry, try again\" {send_user \"Incorrect admin password\";exit 0}
\"password for $admin: $\" {send \"$admin_pwd\r\";exp_continue}
\"password: $\" {send \"$user_pwd\r\";exp_continue}
\"successfully\" {send_user \"Success\"; exit 1}
}
")
echo "Expect's return value : $?"
echo "-----Expect's response-----"
echo $OUTPUT
The Expect's return value will be available in the variable $?. This will help us to know whether the password update is successful or not. The variable OUTPUT, will have the output generated by spawned process.
Use the #!/bin/bash, not #!/usr/bin/expect, since it is actually a bash script.
I was wondering how to use an if/else statement to check if a password is right in my unix shell.
Here is the syntax:
#!/bin/sh
# This is some secure program that uses security.
VALID_PASSWORD="secret" #this is our password.
echo "Please enter the password:"
read PASSWORD
if [ "$PASSWORD" == "$VALID_PASSWORD" ]; then
echo "You have access!"
else
echo "ACCESS DENIED!"
fi
bash-3.2$ Please enter the password:
secr
ACCESS DENIED!
bash-3.2$
bash-3.2$ Please enter the password:
secret
You have access!"
bash-3.2$
Click here for more on if/else syntax in scripts.
read -s -e -p "Enter your password: " PASSWORD
if [ "$PASSWORD" == "password"}; then
echo "You have access!"
fi