Ok, so I have a bash script with an embedded expect statement.
Inside of the expect statement, i'm trying to pull all of the non-comment lines from the /etc/oratab file one at a time.
Here's my command:
cat /etc/oratab |sed /^s*#/d\ | awk 'NR==1'|awk -F: '{print \"$1\"}'|. oraenv
Now, this works at the terminal, but it doesn't work inside of the expect statement.
When executed within the expect script, I get the following error:
missing close-brace
while executing
"while { 1 > 0 } {
#Pull the SIDs from oratab
send "cat /etc/oratab |sed /^s*#/d\ | awk NR==1|awk -F: {print"
couldn't read file """}|. oraenv\r"
expect "?"
send "\r"
expect "$"
I think the issue is with the "awk -F: '{print $1}' " command.
I've tried escape characters, quotes, backticks, quotes with escape characters... any help or ideas would be greatly appreciated!
Here's the complete script for reference:
#!/bin/bash
#set a timestamp that will be used for labeling the log file
timestamp=$(date +%Y-%m-%d-%H:%M:%S)
#set log_file variable; logs will be stored under /var/log/change_password/day-and-time-run.log
log_file="./change_password_$timestamp.log"
#set a variable to hold the number of entries in ORATAB
numDatabases=$(echo cat /etc/oratab | sed '/^\s*#/d;/^\s*$/d' |grep -v "#"|awk -F: '{print $1}'|wc -l)
echo "---------- $numDatabases DATABASES FOUND!!!"
#Ask user to confirm that they have updated the host list (host_list)
echo -n "---------- Welcome to the Password Change Script. Have you edited the host_list file? (Y or N):"
#Collect user's input
read answer
#handle user's input; proceed with collecting CURRENT password if 'Y', otherwise send message and exit
if [ "$answer" = "Y" ]
then
#Prompt user for CURRENT password - will be used to log in at the OS level
echo "---------- Enter the CURRENT password and press [Enter] NOTE - The password must be the same for all user account on all servers and databases to work correctly"
echo -n "---------- Current Password:"
read current_password
fi
if [ "$answer" != "Y" ]
then
echo "---------- You must edit the host_list file first! Exiting!"
exit
fi
#Prompt user for NEW password that will be set for several OS user accounts and DB accounts
echo "---------- Enter a NEW password to be applied to all accounts (OS, DB, RMAN) and press [Enter]"
echo -n "---------- New Password:"
read new_password
#Get the number of servers from the text file, based on number of lines
server_count=$(wc -l < host_list)
#Communicate to user the number of servers found
echo "---------- Changing passwords on "$server_count" servers..."
#Notice to users not to prematurely kill the process/script, as sometimes it appears to be hung/crashed
echo "---------- Do not kill the process/command until you see the 'Goodbye' message - you will see several ssh connections and password updated successfully messages. Starting in 3 seconds..."
#wait 3 seconds
sleep 3
#create 'i' variable for iteration
i=1
#Execute the code within the while loop for every server name found in host file
while [ $i -le $server_count ]; do
#set current_server variable to the server name found on each line of the host_list file
current_server=$(sed -n "$i"p host_list)
#communicate to user/log that script is attempting to SSH to the server and change passwords
echo "---------- Attempting to connect to server "$current_server" ("$i" of "$server_count" servers) and reset password for all accounts..."
#set VAR variable - it will hold the entire expect script command that will SSH to every server and remotely execute password change commands
VAR=$(expect -c '
# Set the log file.
log_file '$log_file'
send_user "\n------------- '$numDatabases' = numDatabases\n"
#start an SSH session as root on the current server
spawn ssh oracle@'$current_server'
#Script has initiated an SSH session; if prompted with the RSA warning, send yes and enter.
#If prompted for password to login, send password and enter
expect {
"The authenticity of host" {send "yes\r"}
"password:" {send "'$current_password'\r"}
}
#Script has attempted to authenticate via SSH by passing a password. If prompted for password again, password must be wrong.
#If prompted with the # then script must have successfully connected to server. Change the OS password for user account oracle
expect {
"password:" {send_user "\n---------- SSH failed - most likely due to incorrect password! Exiting!\n"; exit }
"$" {send "passwd oracle\r"}
}
#Script has attempted to change OS password for user account oracle.
#If prompted for password, OS is ready for new password; send new password and enter.
#If OS returns Unknown user... then oracle user account probably doesnt exist
expect {
"password:" {send "'$new_password'\r"}
"Unknown user name oracle." {send_user "\n---------- passwd failed - there is no user oracle on host $current_server! Exiting!\n"; exit}
}
#Script has supplied the new password for oracle once, just needs to send again to confirm
expect "password:"
send "'$new_password'\r"
#Script will now change password for asm OS user account
expect "$"
send "passwd applmgr\r"
expect {
"password:" {send "'$new_password'\r"}
"Unknown user name applmgr." {send_user "\n---------- passwd failed - there is no user applmgr on host $current_server! Exiting!\n"; exit}
}
#Script has supplied the new password for applmgr once, just needs to send again to confirm
expect "password:"
send "'$new_password'\r"
expect "$"
#Script will now log in to each oracle database and change DB user passwords there
#Looping through all of the databases in oratab
while { '$numDatabases' > 0 } {
#Pull the SIDs from oratab
send "cat /etc/oratab |sed /^s*#/d\ | awk 'NR==1'|awk -F: '{print \"$1\"}'|. oraenv\r"
expect "?"
send "\r"
expect "$"
#log on as sysdba
send "sqlplus / as sysdba\r"
#Expecting the oracle prompt
expect ">"
send "ALTER USER sys IDENTIFIED BY '$new_password';\r"
expect ">"
send "ALTER USER system IDENTIFIED BY '$new_password';\r"
expect ">"
send "ALTER USER dbsnmp IDENTIFIED BY '$new_password';\r"
expect ">"
send "ALTER USER outln IDENTIFIED BY '$new_password';\r"
expect ">"
send "quit\r"
#End while/for loop
}
expect "$"
#If we havent exited by now, everything should be OK - send the all clear message
send_user "\n---------- No errors while changing passwords on $current_server\n"
#Exit the SSH session
send "exit\r"
#Closing the expect statement here
')
#Execute the above expect script
echo "$VAR"
#Notify user/log that all accounts have been updated on current server
echo "---------- Finished with "$current_server"!"
#Wait one second to allow people to see what's happening
sleep 1
#Increment i so loop hits the next server in the host_list
(( i++ ))
#finish loop
done
#Prompt user to clear all clear-text passwords in the log file
echo -n "---------- Complete! Do you want to clear clear-text passwords from the log files? (Y or N):"
#Collect user's input
read answer
#If user answers 'Y', replace all clear-text passwords with '********'
if [ "$answer" = "Y" ]
then
echo "---------- Scrubbing clear-text passwords from log file..."
sed -i 's/'$new_password'/********/g' $log_file
echo "---------- All clear-text passwords have been masked!"
echo "*************** Script has completed"
echo "*************** Log can be found at $log_file"
echo "*************** GOODBYE"
exit
fi
#If user answers with any other string, warn the user of the clear-text passwords
if [ "$answer" != "Y" ]
then
echo "---------- Log file unmodified. CAUTION - your new password is stored in clear-text the log files!"
echo "*************** Script has completed"
echo "*************** Log can be found at $log_file"
echo "*************** GOODBYE"
exit
fi