how to replace special character in linux variables - shell

#!/bin/bash
read -p "Please Enter you OS Password:" PASSWORD
echo "the password is $PASSWORD"
input: Test$1234
We want the output as Test\$1234

You can use printf "%q" $PASSWORD to "shell-escape" the contents of $PASSWORD. This does not only take care of $, but also other special shell characters, such as !, &, >, etc.
#!/bin/bash
read -p "Please Enter you OS Password:" PASSWORD
PASSWORD=$(printf "%q" $PASSWORD)
echo "the password is $PASSWORD"

You can try with the below command, here sed command will replace $ with \$ and will not replace any other special character so no side effect:-
!/bin/bash
read -p "Please Enter you OS Password:" PASSWORD
PASSWORD=$(echo $PASSWORD |sed 's/\$/\\$/g')
echo "the password is $PASSWORD"

Related

Parse the output of a script and process the last line only before printing

I have a simple CLI tool asking for a master password, and printing a string $USER $PASSWORD only if the master password is correct.
How to reproduce?
Here is a script just for demonstrating my use-case, the real script is in fact a CLI tool on which I have no control:
#!/usr/bin/env sh
printf "Enter master password: "
read -s password
echo
[ "$password" == "MasterPassword" ] && echo "user1 Passw0rd!"
Example of usage:
$ ./my-cli-tool
Enter master password: ********
user1 Passw0rd!
Issue
I don't want the password (Passw0rd!) to be printed on screen. I want to print only the user (user1), and just copy the password (Passw0rd!) to the clipboard (let's say with xclip -sel clipboard).
What I have tried?
If the first line (Enter master password) were not there, I would have done:
./my-cli-tool |
while read -r USER PASSWORD
do
echo $USER
echo -n $PASSWORD | xclip -sel clipboard
done
But my issue is that I should type the master password when the prompt asks for, and so the first line is always printed. I have tried to run ./my-cli-tool | tail -1: the prompt is not shown, although if I type the master password, it only prints user1 Passw0rd!, so I can do the command above to copy the password into the clipboard.
Question
Do you have any idea to:
always show the prompt on screen for the master password
only print the user
copy the password to the clipboard
Expected output
Basically, I would like that kind of output:
$ ./my-cli-tool | solution
Enter master password: ********
user1
And have Passw0rd! copied into my clipboard.
I've simply modified your answer a little bit -
./my-cli-tool | {
x=$(dd bs=1 count=1 2>/dev/null)
while [ "$x" != : ]; do
printf %c "$x";
x=$(dd bs=1 count=1 2>/dev/null)
done
printf %s ": "
while read -r USER PASSWORD
do
echo $USER
echo -n $PASSWORD | xclip -sel clipboard
done
}
Lemme know if it works.
EDIT: Updated logic. Uses dd.

username, password program in bash

I have a program that asks input from user on their username and password then stores it in a text file column one is usernames and column 2 is passwords, i need a command that replaces the password when the user inputs their username and new password, heres what i have
#!/bin/bash
#admin menu
#Register User
echo enter the username of the user you want to register.
read reguser
echo enter the password of the user you want to register.
read regpass
User_Pass="username_pass.txt"
if [ ! -e "$User_Pass" ];
then
echo "Creating Username and Passwords file"
touch $User_Pass
fi
echo "$reguser $regpass" | cat >> $User_Pass
echo user succesfully registered.
#Change Password
echo "Enter the username you want to change the password for"
read change1
change2=$(grep -q $change1 username_pass.txt)
if [ $change2=0 ];
then
echo enter your new password
read newpass
awk -v newpass="$newpass" -v change1="$change1" '$1 ~ change1 {$2 = newpass}' username_pass.txt
#i tried this but it didnt work
echo "password changed!"
else
echo "no such username."
fi
You can use sed
sed -i "s/$change1.*/$change1 $newpass/" username_pass

Expect Script for CLI

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.

BASH - Function to get user password

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.

Exporting a variable with a backslash

I am working on an install script, of the following form:
# get username
echo "Please enter your oracle username:"
read -p "> " username
stty -echo
# get password
echo "Please enter your oracle password:"
read -r -p "> " password; echo
stty echo
# -- Create all text to output to config
finaluser=$usernamelabel$username
finalpassword=$passwordlabel$password
echo -e $finaluser"\n"$finalpassword > $configfile
The problem is, if a password of the form like 'z\2z', it is outputted to $configfile as:
z^Bz
Is there any easy way to avoid this?
Don't embed the \n, and then you don't need the -e option which is also interpreting the \2.
echo "$finaluser" >$configfile
echo "$finalpassword" >>$configfile
or
cat >$configfile <<EOF
$finaluser
$finalpassword
EOF
or a third way if you really want to use a single command
printf '%s\n%s\n' "$finaluser" "$finalpassword"

Resources