bash read does not wait for input - bash

I have this code:
#!/bin/bash
for some_host in $(cat some_list); do
echo $some_host
ssh $some_host sudo cat /etc/some.conf |grep -i something_to_grep
printf "\nPut the input: " read some_input
echo $some_input
done
When I run it, it just continues without waiting for my input. I need to copy/past something form ssh output for further action :/

Change
printf "\nPut the input: " read some_input
to
read -p "Put the input: " some_input
Example
for host in '1.1.1.100' '1.1.1.101' '1.1.1.102'
do
read -p "Enter your input for ${host} " host_input
echo "${host} says ${host_input}"
done

Related

a part string is missing when echo in bash

The bash script is:
echo Updating hostname and IP address ...
echo ${config_template_ip}
echo "ssh-keygen -R ${config_template_ip} -f /home/testusr/.ssh/known_hosts"
echo ${config_template_ip}
The output is
Updating hostname and IP address ...
10.100.224.250
-f /home/testusr/.ssh/known_hosts
10.100.224.250
why didn't "ssh-keygen -R ${config_template_ip} " on STDOUT, and how to solve that?

Why is this while loop not looping?

I have the following bash script deploy.sh:
#!/usr/bin/env bash
# Some useful resources:
# while read ip user pass; do : http://unix.stackexchange.com/questions/92664/how-to-deploy-programs-on-multiple-machines
# -o StrictHostKeyChecking=no: http://askubuntu.com/questions/180860/regarding-host-key-verification-failed
# -T: http://stackoverflow.com/questions/21659637/how-to-fix-sudo-no-tty-present-and-no-askpass-program-specified-error
# echo $pass |: http://stackoverflow.com/questions/11955298/use-sudo-with-password-as-parameter
while read ip user pass; do
echo $ip
sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
echo 'yo'
"
echo 'done'
done < servers.txt
servers.txt contains:
53.12.45.74 my_username my_password
54.12.45.74 my_username my_password
57.12.45.74 my_username my_password
‌‌
From my understanding, the while read ip user pass; do […] done < servers.txt should loop over all three lines of servers.txt.
However, when I try to run it, it only performs one iteration:
ubuntu#server:~$ bash deploy.sh
53.12.45.74
yo
done
ubuntu#server:~$
Why?
If the loop is simply:
while read ip user pass; do
echo $ip
done < servers.txt
it does perform all three iterations:
ubuntu#server:~$ bash deploy.sh
53.12.45.74
54.12.45.74
57.12.45.74
ubuntu#server:~$
sshpass is taking control of stdin or possibly replacing it and causing while loop to lose input from redirected stdin.
To work around this issue, avoid reading from stdin.
First, load the file into an array using a while loop.
while read line; do
entries+=("$line")
done < servers.txt
Next, use for loop to parse the lines and execute sshpass within this loop.
for line in "${entries[#]}"; do
set $line
ip=$1
user=$2
pass=$3
echo $ip
sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
echo 'yo'
"
echo 'done'
done
The second loop doesn't read from stdin.
But I will recommend Rany Albeg Wein answer using a separate descriptor than the current stdin.
while read ip user pass <&3; do
echo $ip
sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
echo 'yo'
"
echo 'done'
done 3<servers.txt
#!/usr/bin/env bash
# Some useful resources:
# while read ip user pass; do : http://unix.stackexchange.com/questions/92664/how-to-deploy-programs-on-multiple-machines
# -o StrictHostKeyChecking=no: http://askubuntu.com/questions/180860/regarding-host-key-verification-failed
# -T: http://stackoverflow.com/questions/21659637/how-to-fix-sudo-no-tty-present-and-no-askpass-program-specified-error
# echo $pass |: http://stackoverflow.com/questions/11955298/use-sudo-with-password-as-parameter
while read ip user pass; do
if [ -n "$ip" ]; then
echo "IP[$ip] USER[$user] PASS[$pass]";
# dont forget to uncomment this two lines here:
#sshpass -p "$pass" ssh $user#$ip -o StrictHostKeyChecking=no -T "
#echo 'yo'
echo ""; # Just a blank line"
echo "done.";
else
echo "Empty value.";
fi
done < servers.txt
So, now it works.

How to call a bash script from another script?

I have two very simple scripts. I have asked this question but people thought I am doing it in different platform. Actually these two scripts are in same folder.
One is source.sh
#!/bin/bash
echo "start"
./call.sh
echo "end"
And second is call.sh
#!/bin/bash
passDir="/etc/passwd"
while read line
do
while true
do
echo "prompt"
#propmt for username
read -p "Enter username : " username
egrep "^$username" $passDir >/dev/null
if [ $? -eq 0 ]; then
echo "$username exists!"
else
userName=$username
break
fi
done
done < user.txt
and user.text file is only two words in two lines
Hello
world
Output:
exisats!
prompt
exisats!
prompt
exisats!
prompt
exisats!
prompt
exisats!
prompt
exisats!
prompt
Until I press Ctrl+d I really appreciate if anyone can tel how I can fix this.
You can reduce this to a minimal example:
#!/bin/bash
while read line
do
echo line is $line
echo "prompt"
read -p "Enter username : " username
echo username is $username
done < user.txt
Now the problem is clear: the script reads everything from user.txt.
Only read should read from user.txt. We can tell read to do this by means of a file descriptor:
#!/bin/bash
exec 3< user.txt # open the file, give it File Descriptor 3
while read -r -u3 line
do
echo line is $line
echo "prompt"
read -p "Enter username : " username
echo username is $username
done
exec 3<&- # close the file

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"

Finding and adding a word to a particular line using shell script with exact format of a file

My problem is to add a username to a file, I really stuck to proceed, please help.
Problem: I am having a file called usrgrp.dat. The format of this file is like:
ADMIN:srikanth,admin
DEV:dev1
TEST:test1
I am trying to write a shell script which should give me the output like:
Enter group name: DEV
Enter the username: dev2
My expected output is:
User added to Group DEV
If I see the contents of usrgrp.dat, it should now look like:
DEV:dev1,dev2
TEST:test1
And it should give me error saying user already present if I am trying to add already existing user in that group. I am trying this out with the following script:
#!/bin/sh
dispgrp()
{
groupf="/home/srikanth/scm/auths/group.dat"
for gname in `cat $groupf | cut -f1 -d:`
do
echo $gname
done
echo "Enter the group name:"
read grname
for gname in `cat $groupf | cut -f1 -d:`
do
if [ "$grname" = "$gname" ]
then
echo "Enter the username to be added"
read uname
for grname in `cat $groupf`
do
$gname="$gname:$uname"
exit 1
done
fi
done
}
echo "Group display"
dispgrp
I am stuck and need your valuable help.
#!/bin/sh
dispgrp()
{
groupf="/home/srikanth/scm/auths/group.dat"
tmpfile="/path/to/tmpfile"
# you may want to pipe this to more or less if the list may be long
cat "$groupf" | cut -f1 -d:
echo "Enter the group name:"
read grname
if grep "$grname" "$groupf" >/dev/null 2>&1
then
echo "Enter the username to be added"
read uname
if ! grep "^$grname:.*\<$uname\>" "$groupf" >/dev/null 2>&1
then
sed "/^$grname:/s/\$/,$uname/" "$groupf" > "$tmpfile" && mv "$tmpfile" "$groupf"
else
echo "User $uname already exists in group $grname"
return 1
fi
else
echo "Group not found"
return 1
fi
}
echo "Group display"
dispgrp
You don't need to use loops when the loops are done for you (e.g. cat, sed and grep).
Don't use for to iterate over the output of cat.
Don't use exit to return from a function. Use return.
A non-zero exit or return code signifies an error or failure. Use 0 for normal, successful return. This is the implicit action if you don't specify one.
Learn to use sed and grep.
Since your shebang says #!/bin/sh, the changes I made above are based on the Bourne shell and assume POSIX utilities (not GNU versions).
Something like (assume your shell is bash):
adduser() {
local grp="$1"
local user="$2"
local gfile="$3"
if ! grep -q "^$grp:" "$gfile"; then
echo "no such group: $grp"
return 1
fi
if grep -q "^$grp:.*\\<$user\\>" "$gfile"; then
echo "User $user already in group $grp"
else
sed -i "/^$grp:/s/\$/,$user/" "$gfile"
echo "User $user added to group $grp"
fi
}
read -p "Enter the group name: " grp
read -p "Enter the username to be added: " user
adduser "$grp" "$user" /home/srikanth/scm/auths/group.dat

Resources