append hostname to /etc/hosts bash - bash

I am trying create a simple bash script that will add a record in the /etc/hosts file of my virtual machine. I've managed to do this successfully manually using:
echo sed -i '2i127.0.0.1 hostname.whatever.com hostname' /etc/hosts
But I would like to create a script that asks for the hostname and then creates it dynamically, for example:
#!/bin/bash
echo "Please enter hostname:"
read hostname
echo sed -i '2i127.0.0.1 $hostname hostname' /etc/hosts
This works fine but I would like to also be able to set the shortname "hostname" also. How would I take the first letters of the hostname variable before the .dot and also echo that in to the file correctly?

Parameter expansion:
read -p "Please enter hostname: " hostname
echo "${hostname%%.*}"
Read into array:
IFS=. read -p "Please enter hostname: " -a hostname
echo "${hostname[0]}"
Both of these solutions uses native bash without forking a new process. The first one is also POSIX compliant, so it will work with /bin/sh.

You can get the name before the dot with cut like:
$ hostname=hostname.whatever.com
$ shortname=`cut -d. -f1 <<< $hostname`
$ echo $shortname
hostname

Related

how to run bash script interactively from url? [duplicate]

I have a simple Bash script that takes in inputs and prints a few lines out with that inputs
fortinetTest.sh
read -p "Enter SSC IP: $ip " ip && ip=${ip:-1.1.1.1}
printf "\n"
#check IP validation
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "SSC IP: $ip"
printf "\n"
else
echo "Enter a valid SSC IP address. Ex. 1.1.1.1"
exit
fi
I tried to upload them into my server, then try to run it via curl
I am not sure why the input prompt never kick in when I use cURL/wget.
Am I missing anything?
With the curl ... | bash form, bash's stdin is reading the script, so stdin is not available for the read command.
Try using a Process Substitution to invoke the remote script like a local file:
bash <( curl -s ... )
Your issue can be simply be reproduced by run the script like below
$ cat test.sh | bash
Enter a valid SSC IP address. Ex. 1.1.1.1
This is because the bash you launch with a pipe is not getting a TTY, when you do a read -p it is read from stdin which is content of the test.sh in this case. So the issue is not with curl. The issue is not reading from the tty
So the fix is to make sure you ready it from tty
read < /dev/tty -p "Enter SSC IP: $ip " ip && ip=${ip:-1.1.1.1}
printf "\n"
#check IP validation
if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "SSC IP: $ip"
printf "\n"
else
echo "Enter a valid SSC IP address. Ex. 1.1.1.1"
exit
fi
Once you do that even curl will start working
vagrant#vagrant:/var/www/html$ curl -s localhost/test.sh | bash
Enter SSC IP: 2.2.2.2
SSC IP: 2.2.2.2
I personally prefer source <(curl -s localhost/test.sh) option. While it is similar to bash ..., the one significant difference is how processes handled.
bash will result in a new process being spun up, and that process will evoke commands from the script.
source on the other hand will use current process to evoke commands from the script.
In some cases that can play a key role. I admit that is not very often though.
To demonstrate do the following:
### Open Two Terminals
# In the first terminal run:
echo "sleep 5" > ./myTest.sh
bash ./myTest.sh
# Switch to the second terminal and run:
ps -efjh
## Repeat the same with _source_ command
# In the first terminal run:
source ./myTest.sh
# Switch to the second terminal and run:
ps -efjh
Results should look similar to this:
Before execution:
Running bash (main + two subprocesses):
Running source (main + one subprocess):
UPDATE:
Difference in use variable usage by bash and source:
source command will use your current environment. Meaning that upon execution all changes and variable declarations, made by the script, will be available in your prompt.
bash on the other hand will be running in as a different process; therefore, all variables will be discarded when process exits.
I think everyone will agree that there are benefits and drawbacks to each method. You just have to decide which one is better for your use case.
## Test for variables declared by the script:
echo "test_var3='Some Other Value'" > ./myTest3.sh
bash ./myTest3.sh
echo $test_var3
source ./myTest3.sh
echo $test_var3
## Test for usability of current environment variables:
test_var="Some Value" # Setting a variable
echo "echo $test_var" > myTest2.sh # Creating a test script
chmod +x ./myTest2.sh # Adding execute permission
## Executing:
. myTest2.sh
bash ./myTest2.sh
source ./myTest2.sh
./myTest2.sh
## All of the above results should print the variable.
I hope this helps.

Shell Script - While Loop / File Reading not working

I have a requirement which should address following points.
I have a file which contains list of IP addresses,I want to read line by line.
For each IP I need to push following commands using SSH (all are Mikrotik devices)
/ radius add service=login address=172.16.0.1 secret=aaaa
/ user aaa set use-radius=yes
Following is my code.
#!/bin/bash
filename="branch"
while IFS= read line; do
echo ${line//}
line1=${line//}
ok='#'
line3=$ok$line1
sshpass -p abc123 ssh -o StrictHostKeyChecking=no admin$line3 / radius add service=login address=172.16.0.1 secret=aaaa
sleep 3
sshpass -p abc123 ssh -o StrictHostKeyChecking=no admin$line3 / user aaa set use-radius=yes
sleep 3
echo $line3
echo $line
done <"$filename"
Branch text file:
192.168.100.1
192.168.101.2
192.168.200.1
Issue: What ever the changes I am doing While loop is only run once.
Troubleshooting/Observations:
Without the SSH command if I run the While loop to read the file " branch " it work fine.
The problem is that a program in the loop also reads data on standard input. This will consume the 2nd and subsequent lines of what's in "$filename".
On the next iteration of the loop, there's nothing left to read and the loop terminates.
The solution is to identify the command reading stdin, probably sshpass and change it to leave stdin alone. The answer by Cyrus shows one way to do that for ssh. If that doesn't work, try
sshpass [options and arguments here] < /dev/null
Another solution is to replace the while with a for loop. This works as long as the branch file only contains IP addresses:
for ip in $(cat branch); do
echo $ip
...
sshpass ...
done

ssh bash receive variable from a remote file

I need to read the variable from a remote file over SSH and compare it. But I get a variable in the wrong format. how to do it correctly?
#!/bin/bash
pass='dpassspass'
user='root#10.10.19.18'
IP="10.2.1.41"
path=/sys/variable/serv
#not work## No such file or directory# write=$(sshpass -p $ovhpass ssh -t $user echo "$IP" > $path)
sshpass -p $pass ssh -t $user << EOF
echo "$IP" > $path
EOF
my_var=$(sshpass -p $pass ssh -t $user "cd /sys_ovh; ./serv.bash")
echo mystart-"$my_var"-myend
read=$(sshpass -p $pass ssh -t $user cat $path)
echo start-"$read"-end
echo start-"$IP"-end
if [ "$read" == "$IP" ]; then
echo "run"
fi
output:
Connection to 10.10.19.18 closed.
-myendt-10.2.1.41
Connection to 10.10.19.18 closed.
-endt-10.2.1.41
start-10.2.1.41-end
Where I make a mistake? How to take data from the SSH?
The vars my_var and read are filled with a string ending with '\r', telling echo to go back to the first column. I think this is a problem with your local script. You can correct that with
tr -d "\r" < myfile > myfile2
Your fundamental problem comes from using unquoted here documents for the commands. You should properly understand in which order the shell interprets these contructs.
ssh remote cmd >file
executes cmd remotely, but first redirects the output from the ssh command to the local file.
ssh remote "cmd >’$file'"
The quotes cause the redirection to be part of the remote command line. The variable file is interpreted first, by the local shell, though.
ssh remote 'cmd >"$file"`
The single quotes prevent the local shell from modifying the command before sending it. Thus, he variable interpolation and the redirection are both handled by the remote shell, in this order.
So your commented-out "not work" command could easily be fixed with proper quoting. However, it will be much more elegant and efficient to use a single remote session, and execute all the commands in one go. Mixing the local variable IP with remote variables calls for some rather elaborate escaping, though. A major simplification would be to pass the value on standard input, so that the entire remote script can be single quoted.
#!/bin/bash
pass='dpassspass'
user='root#10.10.19.18'
IP="10.2.1.41"
result=$(echo "$IP" |
sshpass -p "$pass" ssh -t "$user" '
path=/sys/variable/serv
cat > "$path"
cd /sys_ovh
./serv.bash
cat "$path"')
echo mystart-"${result%$'\n'*}"-myend
echo start-"${result#*$'\n'}"-end
echo start-"$IP"-end
if [ "${result#*$'\n'}" == "$IP" ]; then
echo "run"
fi
The output from the remote shell is two lines; we pick it apart by using the shell's prefix and suffix substitution operators.

Passing Value to a shell script via ssh

I want to pass a value to the shell script via ssh:
I have two Linux machines: machine1 and machine2
I have two scripts on those machines: "script1" on machine1 and "script2" machine2.
I have done ssh setting so I can login to machine2 from machine1 without password
/opt/script1
#!/bin/sh
echo "enter your name"
read name
ssh root#machine2 "/opt/script2 $name"
/opt/script2
#!/bin/sh
echo "$name"
but no string is printing
Please let me know the procedure to do this.
can u try the scripts like this
script1.sh
echo "enter your name"
read name
ssh root#machine2 "/opt/script2.sh $name"
script2.sh
echo $1
Passing command-line parameter to shell script
$0 is the name of the command
$1 first parameter
$2 second parameter
$3 third parameter etc. etc
$# total number of parameters
$# all the parameters will be listed
If i entered my name as Rupert script1 would be doing this
ssh root#machine2 "/opt/script2 Rupert"
Script2 is looking for $name but this has not been set on machine2 so the script will print nothing.
You can edit script2 to the below
#!/bin/sh
name=$1
echo "$name"
You should change the script 1 as following:
#!/bin/sh
echo "enter your name"
read name
ssh root#machine2 `/opt/script2 $name`

Bash script to pass commands remotely via SSH

i'm just starting out with bash & am trying to write a script to search specific files in a server remotely based on: (a)device name and (b) string. my goal is to get all output containing 'string' for the device specified. when i tried the script below just hangs. however, when i run the command directly on the server("grep -i "router1" /var/log/router.log | grep -i "UPDOWN"), it works. any ideas?any ideas?
#!/bin/bash
#
read -p "Enter username: " user
read -p "Enter device name: " dev
read -p "Enter string: " str
while read /home/user1/syslogs
do
ssh "$user"#server1234 'grep -i "$dev" /var/log/"$syslogs" 2> /dev/null | grep -i "$str"'
done
You seem to be mis-using the read command. You don't specify the file to read from as an argument; read always reads from standard input. It's not clear what you want to do with the value you read from the file as a result, but you want something like this:
read -p "Enter username: " user
read -p "Enter device name: " dev
read -p "Enter string: " str
while read fileName; do
# Also: I'm borrowing sputnick's solution to the nested quote problem.
ssh $user#server1234 <<EOF
grep -i "$dev" /var/log/$fileName 2>/dev/null | grep -i "$str"
EOF
done < /home/user1/syslogs
The message Pseudo-terminal will not be allocated because stdin is not a terminal is due to the fact that the stdin of the remote host's shell is being redirected from a here document and that there is no command specified for the remote host to execute, i. e. the remote host first assumes there will be a need to allocate a pseudo-terminal for an interactive login session due to the lacking command (see the synopsis of the ssh man page: ssh ... [user#]hostname [command]), but then realizes that the stdin of its shell is not a terminal since it is redirected from a here document. The result is that the remote host refuses to allocate a pseudo-terminal.
The solution in the given case would be to just specify a shell as a command for the remote host to execute the commands given in the here document.
As an alternative to specifying a shell as a command the remote host could be told in advance that there is no need for the allocation of a pseudo-terminal using the -T switch.
The -t switch, on the other hand, would be necessary only if a specified command expects an interactive login shell session on the remote host (such as top or vim).
- ssh $user#server1234 <<EOF ...
+ ssh $user#server1234 /bin/sh <<EOF ...
+ ssh -T $user#server1234 <<EOF ...

Resources