I'm trying to run a task where I have a script that will add a user to a remote server via ssh.
Here is my code:
#echo off
setlocal enabledelayedexpansion
set username=%1
set password=%2
for /F "tokens=*" %%a in (Linuxhosts.txt) do (
ssh -i svcaccount_id_rsa svcaccount#%%a 'bash -s' < adduser.txt
)
Here are the contents of the adduser.txt file
#!/bin/bash
#========================================================================================================
# This script allows for account creation on a server |
# It also performs error handling to ensure that the user doesn't currently exist on the system. |
# Also provides feedback from the input to verify the entries are correct. |
#========================================================================================================
while true; do
echo -n "Enter username: "
read -r username
/bin/egrep -i "^${username}:" /etc/passwd
if [ $? -eq 0 ]; then
echo "User $username already exists. Please check the username and try again."
else
echo "User $username does not exist. Proceed with account creation."
break
fi
done
adduser "$username"
if [ $? -gt 0 ]; then
echo "Error encountered."
exit 1
fi
echo -n "Enter password: "
read -r -s password
echo "$username:$password" | chpasswd
echo "Password was succesfully set for $username."
if [ $? -gt 0 ]; then
echo "Error encountered. There was a problem with your entry. Please re-run the script and try again."
exit 1
fi
usermod -a -G wheel "$username"
echo "User was succesfully added to the group wheel."
if [ $? -gt 0 ]; then
echo "Error encountered."
exit 1
fi
echo "Successfully added $username to the system."
However, when I try to run the first set of code through a cmd prompt, I get the following error:
bash: line 41: syntax error: unexpected end of file
I'm not sure what I'm missing. I have tested it with another file called hello.txt and it ran fine so I'm wondering if maybe there's spacing issues somewhere that I can't see because it's a text file.
I'm pretty sure the immediate problem here is that the file adduser.txt is in DOS/Windows format, with its lines terminated with a carriage return character, followed by a linefeed. Unix (including bash) expects just a linefeed as the line terminator, and hence treats the carriage return as part of the line's text. In this case, that means that bash sees line 17, "done", as "done[carriage return]" which isn't a valid keyword and does not end the while loop, so it keeps looking for the "done" keyword... until it runs out of file.
(Credit to Squashman for suggesting this in a comment.)
You're likely to have this problem a lot transferring files from Windows to unix; unfortunately, the tools available to fix the problem vary quite a bit depending on what OS you're using, etc.
BTW, I see a couple of other problems here. For one thing, the read commands in the script are going to be trying to read from the same source that bash is reading commands from, which is the adduser.txt file. So when it does e.g. read -r username it's actually going to be reading some later line from the script file, not from the user running the batch script. This is going to be very hard to solve the way you're doing it; I think it'll be much better to actually copy the script file to the unix system, then run it separately.
Also, as Socowi pointed out in the comments, $? gets the exit status of the last command executed, so in sections like this:
echo "$username:$password" | chpasswd
echo "Password was succesfully set for $username."
if [ $? -gt 0 ]; then
...
the if condition is checks the exit status of the command echo "Password was succesfully set for $username.", not the chpasswd command. The same problem applies to the usermod command later. The better way to do this is to use the command you want to check for success directly as the if condition:
if echo "$username:$password" | chpasswd; then
echo "Password was succesfully set for $username."
else
echo "Error encountered. There was a problem with your entry. Please re-run the script and try again."
exit 1
fi
I'd use this same format in all of the places you're checking exit status: the egrep, useradd, chpasswd, and usermod commands.
[UPDATE] After a bit of mulling, I have a couple of possible solutions: First, to fix the carriage return problem, you could pipe the file through tr -d "\r" as a quick-n-dirty CR remover (although you may have to play around with the quoting and/or escaping to get that \r through both batch and bash's command processing). Second, pass the username and password as arguments to the script instead of having it read them. Thus, your batch script would use something like this:
ssh -i svcaccount_id_rsa svcaccount#%%a 'tr -d "\r" | bash -s "username" "password"' < adduser.txt
... then change adduser.txt to use username="$1"; password="$2" instead of the read commands (and also changing that while loop into an if, since there wouldn't be an option to try again with a different username).
Related
I do not know why I am getting an error when I run my script with SSH, but when I run the bash from my CA server everything works fine.
I installed my VPN server based on this article https://www.digitalocean.com/community/tutorials/how-to-set-up-an-openvpn-server-on-ubuntu-18-04
I wrote a bash for the VPN creation but when I try to run it I need to SSH to the other server at some point. If I start the script with SSH in it I got an error message:
>./easyrsa: 341: set: Illegal option -o echo
My bash contain this and run from my VPN server:
sshpass -p $PASSWORD ssh username#"CA server IP" "/home/username/makevpn.sh $NAME $PASSWORD"
And makevpn.sh contain this:
>./easyrsa sign-req client $NAME
After this run it seems okay but give that error above.
I tried to read after this error and found nothing. :( Hope someone can help because I am hopeless after 4 days of troubleshooting.
Code of VPN script
#!/bin/sh
clear
read -p "Please enter the name of the new certificate : " NAME
read -p "Please enter the Password : " PASSWORD
cd /home/username/EasyRSA-3.0.7/
./easyrsa gen-req $NAME nopass
echo "gen-req done"
cp /home/username/EasyRSA-3.0.7/pki/private/$NAME.key /home/username/client-configs/keys/
echo "cp done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/reqs/$NAME.req username#192.168.1.105:/tmp
echo "scp done"
sshpass -p $PASSWORD ssh username#192.168.1.105 "/home/username/makevpn.sh $NAME $PASSWORD"
echo "ssh done"
cp /tmp/$NAME.crt /home/username/client-configs/keys/
echo "last CP done"
sudo /home/username/client-configs/make_config.sh $NAME
echo "All Done"
Code on CA server
#!/bin/sh
NAME=$1
PASSWORD=$2
cd /home/username/EasyRSA-3.0.7/
echo "CD Done"
./easyrsa import-req /tmp/$NAME.req $NAME
echo "Import-req done"
./easyrsa sign-req client $NAME
echo "Sign-req done"
sshpass -p $PASSWORD scp /home/username/EasyRSA-3.0.7/pki/issued/$NAME.crt username#192.168.1.103:/tmp
echo "Scp done"
I was just browsing the code of that easyrsa script here. This one is likely different from yours given the line for the error is 341. On the Github page, it is line 352 and it is part of a function called cleanup. It appears that this function is only attached as a trap (line 2744). Traps are used to catch signals like sigint (interrupt) which is normally sent on the terminal with ctrl+c (and may display a character like ^C). The reason the error only displays in your script is it likely causes a signal to be emitted that you would not normally receive if you ran it manually over ssh.
The error itself is really not an issue.
Code from Github:
Line 352:
(stty echo 2>/dev/null) || { (set -o echo 2>/dev/null) && set -o echo; }
Line 2744:
trap "cleanup" EXIT
It appears that line is just trying to turn terminal output of your typed characters back on (via stty echo). Sometimes programs will disable terminal output somewhere, and then re-enable it when the program finishes. However, if you were to kill the program mid way through (e.g. with ctrl+c), your program would terminate with the terminal output still disabled. This would make the terminal appear to be frozen. It would still work, but would not display the characters you type with your keyboard. The point of the trap is to ensure that terminal output is re-enabled no matter how the program exits.
More info...
At line 567 there is a function that disables echo. Looks like the point is to not show a password to the screen. If you were to kill the program during password reading, echo would remain disabled on the terminal. Likely the reason for the error has more to do with the way you are running the script. For whatever reason it causes stty echo to fail. Line 352 is assuming that the failure is due to stty echo not being a valid command. So on failure ( || ), it tries a different method (set -o echo) of enabling echo. If I try to run that on my terminal, I also get an error (bash 4.2):
-bash: set: echo: invalid option name
I want to make a simple bash script that makes a for loop over a file with commands and execute those commands, and finishes when an error happens. I have something like this
#!/bin/bash
while IFS= read -r line; do
echo $line
output=$(eval $line)
if [ $? -eq 0 ]
then
echo ok
else
echo $output
break
fi
echo
done < summary.txt
The problem is that the first command I'm trying to make is a sudo command, so I have to put the password. I tried putting it in the command like
sudo -S <<< password <<< Y command
with no luck. I've checked that works if I just put it directly without having to read it (not putting it as a string). The thing is that without the loop, the program would be long with no much sense.
Thanks
echo <password> | sudo -S < your command>
From man sudo
-S, --stdin
Write the prompt to the standard error and read the password from the standard input instead of using the terminal
device. The password must be followed by a newline character.
This bash script when run on Mac terminal, it needs to ask for user input, then it needs to check if a a string "PLACEHOLDER_BACKEND_NAME="user-input" exists in a given file and if not it should exit the script.
echo -e "${YELLOW}enter app name${WHITE}"
read name
line=grep $name /path/to/file/entrypoint.sh
if [[ line != "PLACEHOLDER_BACKEND_NAME=\"$name\"" ]] ; then
exit 1
fi
It needs much tuning as I am not very familiar with bash scripts. any suggestions? thx
Your code needs a little tweaking:
echo -e "${YELLOW}enter app name${WHITE}"
read -r name
if ! grep -q PLACEHOLDER_BACKEND_NAME="\"$name\"" /path/to/file/entrypoint.sh; then
exit 1
fi
I have a scenario to copy file from one server to another, for that i need to check any existing scp is in progress, have wrote a sample shell script but the condition is not being met even though syntax is correct, the main problem here is the output of ps command will gets stored in variable scpstat and the same compared for matching string in if statement, here I'm getting the output of the variable is different from executing outside of the script. can see it is formatted different in script execution when executing sh -x scpsamp.sh, why there is "sh" appended to the output, but while comparing without ps and assigning as scpstat='scp' i can able to get the condition correct, am i doing anything wrong while getting output in to the variable. please help
#!/bin/sh
scpstat=`ps -ef | grep scp | egrep -v 'grep|ssh' | awk '{print $8}')`
if [ "$scpstat" = "scp" ];
then
echo "SCP is in progress"
else
echo "No SCP in progress"
fi
sh -x output
It's notoriously difficult to extract information from the output of ps. If your system has pgrep, it's much easier:
if pgrep scp >/dev/null
then
echo "SCP is in progress"
else
echo "No SCP in progress"
fi
I have created a script for updating some ipaddress in iptables. Hereby I'm describing the issues which I'm facing with that.
Issues:
Comparison not happening between two variables within a script
At the end of script i need to execute a command ie; service restart/stop etc and output of the commands should be visible while executing the script.
1) Here am comparing two variable strings:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
but there is no response/output while executing the above script. Here its not comparison is not happening..Kindly suggest a best solution to resolve this issue.
2) after executing the script I need to restart the iptables:
BASE=172.31.0.0
CMD=172.31.1.0
if [[ "$CMD" == "$BASE" ]]; then
echo "ip are same"
else
echo "not matched"
fi
service iptables restart
iptables -nvL
A script should display the output of the last two lines (commands). Kindly suggest me the best solution and how to do this in a best way.
That's very odd. This should work, so if it's not working you forgot to mention something important.
How is this script being executed? Do you simply type ./script or is it executed by some service (like cron)?
Here are some of suggestions to debug:
Sanity check: see if bash works (perhaps your login shell isn't bash, so you didn't notice). Run this at the terminal:
/bin/bash -c 'echo hello world'
It prints hello world, right? How about this:
/bin/bash -c 'BASE=172.31.0.0; CMD=172.31.1.0; if [[ "$CMD" == "$BASE" ]]; then echo "ip are same"; else echo "not matched"; fi'
If any of the above doesn't work, you have a problem with your bash installation.
Instead of executing your script with ./script.sh, run it like this:
/bin/bash script.sh
Nothing? Run this:
file script.sh
If it ends with something like "with CRLF line terminators", then cdarke nailed it: the file was created on Windows with an improper tool. Recreate it on Linux or use dos2unix. But anyway, I doubt it because with a CRLF-ending file I get this printed:
bash: ./script.sh: /bin/bash^M: bad interpreter: No such file or directory
Instead of nothing at all.
Put those this line on the beginning of the file:
set -x
(below #!/bin/bash, if you have it). This ensures a debugging trace will be printed, showing each command as it is executed.
If still there is nothing shown.. put this at your script (below set -x if you put it):
touch /tmp/hi-this-is-strange
Then check if there is a /tmp/hi-this-is-strange file after you run the script.