Trying out my first BASH script, keep getting unexpected end of file - linux

I was trying to make a script that would pretty much automate this process:
http://knowledgelayer.softlayer.com/procedure/add-additional-ips-redhat
Wasn't too sure how well it would work, but didn't get too far before I could get the script to one. Below is the content of the script:
Editing with updated code:
Edit#2: Got it mostly working, however now it runs the loop and skips over the read propmt to get the static IP
#!/bin/bash
path=/etc/sysconfig/network-scripts/
echo "Let's get your IP added :)"
echo""
getnewip()
{
echo read -p "Enter the new IP Address you wish to add: " staticip
}
getserverinfo()
{
gateway=$(netstat -rn | sed -n 3p | awk '{print $2}')
netmask=$(ifconfig eth1 | grep -i 'netmask' | grep -v '127.0.0.1' | awk '{print $4}')
clone=$( ifconfig | grep eth1 | awk '{print $1}' | cut -d: -f2 )
}
rangechecks()
{
cd /etc/sysconfig/network-scripts/
ls ifcfg-eth1-range*
filename==$1
if [[ ! -f $filename ]]; then
touch "$filename"
echo "Created \"$filename\""
fi
digit=1
while true; do
temp_name=$filename-$digit
if [[ ! -f temp_name ]]; then
touch "$temp_name"
echo "Created $path\"$temp_name\""
digit=$((digit + 1 ))
fi
done
}
writeinterfacefile()
{
cat >> "/etc/sysconfig/network-scripts/$1" << EOF
IPADDR_START=$staticip
IPADDR_END=$staticip
NETMASK=$netmask
CLONENUM_START=$((clone+1))
EOF
echo ""
echo "Your information was saved in the file '$1'."
echo ""
}
{
clear
getserverinfo
echo ""
echo "Please verify this information: "
echo "Gateway Address: " "$gateway"
echo "Netmask: " "$netmask"
echo "Your new IP: " "$staticip"
echo ''
while true; do
read -p "Is this information correct? [y/N]" yn
case $yn in
[Yy]* ) $writeinterfacefile;;
[Nn]* ) print "$getserverinfo" && exit ;;
* ) echo 'Please enter Y or n';;
esac
done
}
I'm fairly new at scripting, so excuse the horrid syntax. My eye is on that EOF but I have no clue.

rangecheckshas no }, your while has no done...
You should indent your code. I started doing that, and noticed the error right away.
Other things:
Single quotes don't expand variables, '/etc/sysconfig/network-scripts//$1 won't do what you want it to.
echo "" is equivalent to echo.
foo='bar'; echo "blah" echo -n $foo will output 'blah echo -n bar'.
exit exits the script, I'm not sure that's what you think it does.
[y/N] usually means N by default (the capital letter).
Also, you then ask to enter Y or n. Be consistent!
When using a variable as a parameter, double quote it. This ensures it stays the way it is (as one parameter, and not expanded by the shell).

I can't see the closing curly brace of function rangechecks
Also, don't indent the shebang in the first line.

Related

How to use error validation in Bash for checking an entry in a file

#!/bin/bash
echo 'Please enter the name of the species you are looking for: '
read speciesName
grep "$speciesName" speciesDetails.txt | awk '{print $0}'
echo
echo 'Would you like to search for another species? Press y to search or n to go back
to the main menu: '
read answer
case $answer in
[yY] | [yY][eE][sS] )
./searchSpecies.sh;;
[nN] | [nN][oO] )
./speciesMenu.sh;;
*) echo exit;;
esac
If there is no entry of that species name in the file how do I give the user an error to say not found?
The answer to your immediate question is to examine the exit code from grep. But probably also refactor the loop:
#!/bin/bash
while true; do
read -p 'Please enter the name of the species you are looking for: ' -r speciesName
grep -e "$speciesName" speciesDetails.txt || echo "$speciesName: not found" >&2
read -p 'Would you like to search for another species? Press n to quit: ' -r answer
case $answer in
[nN] | [nN][oO] )
break;;
esac
done
A better design altogether is probably to make the search term a command-line argument. This makes the script easier to use from other scripts, and the user can use the shell's facilities for history, completion, etc to run it as many times as they like, and easily fix e.g. typos by recalling the previous invocation and editing it.
#!/bin/bash
grep -e "$1" speciesDetails.txt || echo "$1: not found" >&2
The short-circuit one || two corresponds to the longhand
if one; then
: nothing
else
two
fi
If you want to search for static strings, not regular expressions, maybe add -F to the grep options.
If you need just check existance then execute it using next way :
if grep speciesName4 speciesDetails.txt; then
echo "exist";
else
echo "Not exist";
fi
Use $? to check exit code of the command if you need return value as well
set -o pipefail
$ echo "speciesName1" > speciesDetails.txt
$ echo "speciesName2" >> speciesDetails.txt
$ echo "speciesName3" >> speciesDetails.txt
$ l_result=$(grep speciesName3 speciesDetails.txt); l_exit_code=$?
$ echo $l_exit_code
0
$ l_result=$(grep speciesName4 speciesDetails.txt); l_exit_code=$?
$ echo $l_exit_code
1
Updated:
It is not antipattern if you need to use later output of your command

Linux "echo -n" not being flushed

I have the following code:
while ...
echo -n "some text"
done | while read; do
echo "$REPLY" >> file
done
but echo works only when used without "-n" flag.
looks like when using -n, the output is not flushed/read by next while loop
How can I make sure that "some text" will be read even when not followed by EOL?
You can't distinguish between
echo -n "some text"
and
echo -n "some t"
echo -n "ext"
so you need some kind of delimiting rule. Usually EOL is used for that. read supports custom delimiter via -d or can split based on number of chars via -n or -N. For example you can make read fire on each symbol:
echo -n qwe | while read -N 1 ch; do echo $ch; done
The workaround would be (following original example):
while ...
echo -n "some text"
done | (cat && echo) | while read; do
echo "$REPLY" >> file
done
This will append EOL to the test stream & allow read to read it.
The side effect will be an additional EOL at the end of stream.
You can start with defining your own delimiter:
while :; do
echo -n "some text"
sleep 2
done | while read -d' ' reply; do
echo "-$reply-"
done
This prints:
-some-
-textsome-
-textsome-
For an email perhaps it makes sense to use . as a delimiter, but you need to decide on some tokenization scheme.
You can make read read one char a time, but should add something for reading special characters (newlines, spaces): IFS=.
I want to show that I really capture the characters, so I will uppercase the replies.
i=0
while (( i++<5 )) ; do
echo -n "some text $i. "
sleep 1;
done | while IFS= read -rn1 reply; do
printf "%s" "${reply^^}"
done
This solution has one feature: You will not see any newlines.
When you want to see them too, you need to fix this with
i=1
while (( i++<5 )) ; do
echo -n "some text $i.
second line."
sleep 1;
done | while IFS= read -rn1 reply; do
if (( ${#reply} == 0 )); then
echo
else
printf "%s" "${reply^^}"
fi
done

sed is not working for commenting a line in a file using bash script

I have created a bash script that is used to modify the ulimit of open files in the RHEL server.
so i have reading the lines in the file /etc/security/limits.conf and if the soft/hard limit of the open files are less than 10000 for '*' domain i am commenting the line and adding a new line with soft/hard limit as 10000.
The Script is working as designed but the sed command to comment a line in the script is not working.
Please find the full script below :-
#!/bin/sh
#This script would be called by '' to set ulimit values for open files in unix servers.
#
configfile=/etc/security/limits.conf
help(){
echo "usage: $0 <LimitValue>"
echo -e "where\t--LimitValue= No of files you want all the users to open"
exit 1
}
modifyulimit()
{
grep '*\s*hard\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
grep '*\s*soft\s*nofile\s*' $configfile | while read -r line ; do
firstChar="$(echo $line | xargs | cut -c1-1)"
if [ "$firstChar" != "#" ];then
hardValue="$(echo $line | rev | cut -d ' ' -f1 | rev)"
if [[ "$hardValue" -ge "$1" ]]; then
echo ""
else
sed -i -e 's/$line/#$line/g' $configfile
echo "* hard nofile $1" >> $configfile
fi
else
echo ""
fi
done
}
deleteEofTag(){
sed -i "/\b\(End of file\)\b/d" $configfile
}
addEofTag()
{
echo "#################End of file###################" >> $configfile
}
#-------------Execution of the script starts here ----------------------
if [ $# -ne 1 ];
then
help
else
modifyulimit $1
deleteEofTag
addEofTag
fi
The command sed -i -e 's/$line/#$line/g' $configfile when executed from the terminal is working absolutely fine and it is commenting the line but it is not working when i am executing it from the unix shell script.
interpolation does not work in single quote
use double quote and try
sed -i -e 's/$line/#$line/g'
sed -i -e "s/$line/#$line/g"
also you might try:
sed -i -e s/${line}/#${line}/g
as this will tell the script to take the value of the variable instead of variable as such.

Centos add multiple interfaces from file to VLANs

I write script, that will create CentOS interfaces from file with list of IP addresses. In loop, i create file, next action, i add data for centos interfaces. Look:
from=/root/ip
inter=`cat /proc/net/dev | grep "eth0:\|venet0" | awk '{ print $1 }' | sed 's/://g'`
eth=`ifconfig | grep $inter | tail -1 | awk '{ print $1 }' | sed "s/$inter://g"`
echo "Last number of interface: $eth"
if [ "$eth" == "eth0" ]; then
eth_temp="-1"
else
eth_temp=$eth
fi
if [ "$inter" == "eth0" ]; then
echo "Name of interface: $inter"
echo "Add IP to interfaces"
if [ -f $from ]; then
for IP_TO_ETH in `grep -v ^# $from`; do
eth_temp=$(($eth_temp+1))
cent_int=`touch /etc/sysconfig/network-scripts/ifcfg-$inter:$eth_temp`
cat >> $cent_int <<END
DEVICE=eth0:$eth_temp
ONBOOT=yes
BOOTPROTO='static'
IPADDR=$IP_TO_ETH
NETMASK=255.255.255.0
END
done
else
echo "File does not exist"
fi
elif [ "$inter" == "venet0" ]; then
echo "Name of interface: $inter"
echo "This interface from OpenVZ. Not need to add"
else
echo "Other name of inteface"
fi
All ok. But it is not working. When i start bash/sh -x, i receive this:
cent.sh: line 28: $cent_int: ambiguous redirect
+ for IP_TO_ETH in '`grep -v ^# $from`'
+ eth_temp=61
++ touch /root/network-scripts/ifcfg-eth0:61
+ cent_int=
+ cat
cent.sh: line 28: $cent_int: ambiguous redirect
+ for IP_TO_ETH in '`grep -v ^# $from`'
+ eth_temp=62
++ touch /root/network-scripts/ifcfg-eth0:62
+ cent_int=
+ cat
Where i have error ? Please help. In ubuntu it is simply, because all will write in one file. But in CentOS, it is too difficult for me.
When you write:
variable=`command`
it sets the variable to the output of the command. But touch doesn't produce any output, so
cent_int=`touch /etc/sysconfig/network-scripts/ifcfg-$inter:$eth_temp`
assigns an empty string to cent_int. I think what you want is:
cent_int=/etc/sysconfig/network-scripts/ifcfg-$inter:$eth_temp
You don't need to use touch, since writing to the file with cat >> $cent_int will create the file if it doesn't already exist.

Switch case: Confusing error in "Syntax error: word unexpected (expecting "in")"

This is my code:
echo
echo "WELCOME"
echo "-------------------------------------------------"
while true
do
echo
echo "Select A Menu Option"
echo "1: Ancestry History"
echo "2: Who is Online"
echo "3: What Process Any User is Running"
echo "4: Exit"
read mOption
case $mOption in
1) echo
echo "The Ancestry Tree For Current Process is....";
ps -ef > processes
grep "ps -ef" processes > grepProcesses
awk '{print $2, $3}' processes > awkProcesses
PID=$(awk '{print $2}' grepProcesses)
echo $PID
SPID=$(awk '{print $3}' grepProcesses)
PID=$SPID
end=0
while [ $end != 1 ]
do
echo " | "
echo $SPID
PID=$SPID
SPID=$(grep ^"$PID " awkProcesses | cut -d' ' -f2)
if [ "$PID" = "1" ]
then
end=1
fi
done
rm processes
rm grepProcesses
rm awkProcesses
;;
2) echo
echo "Users Currently Online";
who | cut -d' ' -f1
;;
3) echo
echo "Select a Currently Online User to View their Processes:"
index=0
who | while read onlineUser
do
echo "$index-$onlineUser" who|cut -d' ' -f1>>userList
index=$((index+1))
done
awk '{ print $0 }' userList
read choice
if [ $choice ]
then
echo
echo ***Process Currently Running***
person=$(grep ^$choice userList |cut -d'-' -f2)
ps -ef >> process
grep $person process
else
echo You have made a mistake. Please start over.
fi
rm userList
rm process
;;
4) echo
echo "Exiting..."
exit 1;;
*)
echo
echo "Invalid Input. Try Again."
;;
esac
done
Each time I run it I just keep getting the syntax error "hmwk1.sh: 17: hmwk1.sh: Syntax error: word unexpected (expecting "in")"
I looked up different syntax examples and it seems that my code looks correct. But my trial and error gets me nowhere to fixing my code.
Could I be missing a parenthesis or quotation marks of some kind?
If you simply press return on the prompt
read mOption
case $mOption in
then $mOption is an empty token, making the shell see just
case in
which is a syntax error. If you add
test -z "$mOption" && continue
in the middle, if will repair that problem.

Resources