clear memory with variable - bash

Currently I'm creating a little script in BASH that will ask the user to fill in a new IP-address, subnet and gateway. That input goes to a file which will be writen to /etc/network/interface..
I got the script working, but it isn't bullet proof.
When the user input, is not a number but an alphabetic character, It returns and the user needs to fill again a number.
When the user still uses a alphabetic character, the script continues, even though giving a error.
My code:
echo "Fill in your IP"
read NEW_IP
oldIFS=$IFS
IFS=.
set -- $NEW_IP
while [ $# -ne "4" ]; do
echo "Must have 4 parts"
read NEW_IP
set -- $NEW_IP
done
for oct in $1 $2 $3 $4; do
echo $oct | egrep "^[0-9]+$" >/dev/null 2>&1
while [ "$?" -ne "0" ]; do
echo "$oct is not numeric. fill your IP in the correct format;"
read NEW_IP
set -- $NEW_IP
done
I'm new with bash, above I didn't make it by my self. I've found this script on the internet. The while and do, I made that by my self as a loop.
Everytime the user fills in a wrong number It must return untill the user filled in a correct format.
The real problem lies at the second half of the code. When I fill in a wrong IP like 10.10.10.a, I get the error like I want and I have to fill in for the second time my IP.
When I type 10.41.12.r, an error occured but this time, not complaining about the r at the end, but still complaining about the a which I inserted at the first. 10.41.12 will be checkt, but that last character is different.
I can imagine that everything will be stored in memory, but how do I clear that?
unset or $oct=
won't work
Hope that someone can help me with this. It's my first time programming, and this is giving me a headache
thanks.
Dave

for does not evaluate the condition several times. It just runs 4 times, setting $oct to $1 .. $4. If you try several times, your input will be accepted, even if not numeric. Moreover, you should check "Must have 4 parts" again after getting the input in the loop.
BTW, you should check that each $oct <= 255.

Duplicated code is often bad. Better read the input at one place and go through the same tests everytime.
prompt="Fill in your IP"
while
echo $prompt
read NEW_IP
IFS=.
set -- $NEW_IP
IFS=
if [ $# -ne 4 ]
then
prompt="Must have 4 parts"
continue
fi
for oct
do if [[ ! "$oct" =~ ^[0-9]+$ ]]
then
prompt="$oct is not numeric. fill your IP in the correct format;"
continue 2
fi
# You might add more checks here.
done
do break
done

Related

Problems with BASH variable multiplication inside if statment

I am having an issue getting BASH to update a variable in a piece of scripting that I am working on. Below is an excerpt from my script that I have having troubles with
read -p "Did you plan on running the server from a Ramdisk?(y/n)" RAMDISK
if [[ "$RAMDISK" == [yY] ]]; then
read -p "What is the full path to where you would like to create the ramdisk?(/var/RAMDISK)" RAMDIR
read -p "How big did you want the ramdisk to be?(2048)" RAMSIZE
if [[ "$RAMSIZE" -lt 1024 ]]; then
$NEWRAMSIZE = $((RAMSIZE*1024)) #FIXME
echo $NEWRAMSIZE
fi
RAMDISK="Enabled"
fi
if [[ "$RAMDISK" == [nN] ]]; then
RAMDISK="Disabled"
fi
echo $NEWRAMSIZE
My problem is that no matter what I am trying, the RAMSIZE variable never gets multiplied by 1024. I am trying to make it so no matter what number you enter, it will always get changed to a size in mb instead of gb, assuming anything less than 1024 is a gb size. Earlier in the script RAMSIZE defaults to 2048 and it never seems to be changed during the if statement. Please help?
I see three problems: you shouldn't have spaces around the = in an assignment, you shouldn't use $ on the variable you're assigning to ($variable is how you get the value of a variable, not how you set it), and you're using RAMSIZE in some places and NEWRAMSIZE in others. The critical lines are:
if [[ "$RAMSIZE" -lt 1024 ]]; then
RAMSIZE=$((RAMSIZE*1024)) # Note: no spaces, no extra $, same variable
echo $NEWRAMSIZE
fi
...
echo "$RAMSIZE" # Same variable
BTW, you can use shellcheck.net to spot basic problems like this.

Is [ $var ] an acceptable way to check for variables set/empty in bash?

I wrote some bash before reading this popular question. I noticed the way I was doing things doesn't show up in any of the answers so I was curious if there is a danger/bug to my logic that I am not seeing.
if [ ! $1 ] || [ $2 ]; then
echo "Usage: only one var." && exit 1
fi
As you can see, I am testing to see if there is one and only one parameter given on the command line. As far as I have tested, this works. Can someone pass along some more knowledge to a new bash user?
./script one '' oops
[ $2 ] will be false when $2 is the empty string.
And as that other guy points out in a comment, bash will split both strings, opening up a range of issues, including potential security holes.
This is clearer:
if [ $# != 1 ] ; then
echo "Usage: only one var."; exit 1
fi
Things that will break your test:
The first parameter is empty ("")
The second parameter is empty ("")
The first or second parameter has more words ("bla bla")
The parameters contain something that will be interpreted by test (e.g.: -z)
It is simply less clearer than using $#. Also the mere fact that I have to think about all the corner-cases which could potentially break the code makes it inferior.

Basic Bash script exiting prematurely. Worked fine until a half hour ago

I have having an interesting issue that I can't seem to figure out.
I have a basic script that pulls configuration information and just redirects it to a file:
cat /etc/something > 1
cat /etc/something-else > 2
As soon as my data gather is finished, I run a "parser" that presents info about the check:
#58
id="RHEL-06-000001"
ruleid="The system must require passwords to contain at least one special character."
if grep -G [a-z] 1; then
ocredit=`cat 1 | grep -v "^#" | awk '{print $2}'`
if [ "$ocredit" -le -1 ]; then
result="Not A Finding"
todo="None"
else
result="Open"
todo="The current value is $ocredit. This is less than the minimum requirement of - 1."
fi
else
result="Open"
todo="The option is not configured"
fi
echo "$id, $ruleid, $result, $todo" >> Findings.csv
#59
id="RHEL-06-000002"
ruleid="The system must require passwords to contain at least one lowercase alphabetic character."
if grep -G [a-z] 2; then
lcredit=`cat 2 | awk -F"=" '{print $2}'`
if [ "$lcredit" -le -1 ]; then
result="Not A Finding"
todo="None"
else
result="Open"
todo="The current value is $lcredit. This is less than the minimum requirement of -1."
fi
else
result="Open"
todo="The system is not configured to require at least one lowercase alphabetical charatcer in passwords."
echo "$id, $ruleid, $result, $todo" >> Findings.csv
Or something remotely close to that.
I have roughly 250 of these checks happening but my code is runs the first 58 and then stops and no longer redirects content to the checks.csv.
I do get an error after the script finishes prematurely, stating
./checker.sh: line 2898: syntax error: unexpected end of file
which is the end of my file, but I can't seem to figure out how it is escaping to that point in the script.
The kicker, this all worked until about a half hour ago and it has be stumped.
Can you help me out?
You seem to be missing the fi after your second-last line:
else
result="Open"
todo="The system is not configured to require at least one lowercase alphabetical charatcer in passwords."
## HERE ##
echo "$id, $ruleid, $result, $todo" >> Findings.csv
That could potentially cause problems for the bash parser when encountered, causing an EOF error when bash tries to find the missing fi.
That probably means you've got an unclosed if statement or similar. Bash reads simple commands on-demand, but when it comes upon a complex statement like that, it wants to read the whole if statement and its contents. If it then comes upon an EOF while still trying to read to the end of it, it will give you that error.

How to find files containing empty strings

One of our suppliers has a buggy shop floor system (long story short). While they fix whatever is wrong on their end, I need to segregate files they send: they are not empty but have a long empty string. Typically a good file will look like this in vi
<insert_list><test_event_insert endTime="2012-09-10T05:28:45" startTime="2012-09-10T05:27:41" operator="8176967"><process_step name="FVT" revision="NO DATA"></process_step><location1 name="CT" type="REGION"><location2 name="ONTREP1" type="TESTER"><location3 name="LineA" type="LINE"></location3></location2></location1><unit ...
"CT~DCA~FVT~8176967~ONTREP1~4~P~1100~DECA1MR0-01~XED1B1033A4675~20120910~052846.XML" [noeol][dos] 3L, 2170C
a bad file will look this:
^#^#^#^#^#^#^#^#^#^#^#^#^#...
"CT~DCA~FVT~8176967~ONTREP1~2~P~1100~DECA1MR0-01~XED1B1045B6072~20120904~043209.XML" [noeol] 1L, 2170C
The caret/at sign combo is VI's interpretation of that string, I guess but it is in fact an empty string. Using -z seems to work on one single file
X=CT~DCA~FVT~8176967~ONTREP1~2~P~1100~DECA1MR0-01~XED1B1045B6072~20120904~043209.XML
if [ ! -z $X ]
then
echo "$X empty"
else
echo "$X not empty"
fi
CT~DCA~FVT~8176967~ONTREP1~2~P~1100~DECA1MR0-01~XED1B1045B6072~20120904~043209.XML empty
But the same code is telling me that all 900 files on my EMC mass filer are empty. Which is not true.
export OUT=/path/to/device
declare -a myArray
for f in "$OUT"/*ONTREP1*; do myArray+=( "${f#$OUT/}" ); done
for i in "${myArray[#]}"; do if [ ! -z $i ] ; then echo "$i empty"; else echo "$i not empty"; fi; done
NB: Pattern "ONTREP1" is to narrow down the faulty files to one shop floor computer name.
What am I missing?
You are missing that test -z string tests whether a string is empty (as opposed to test -s file which tests whether a file is empty.) Furthermore the ^# in vim are an indication of NUL bytes--bytes with the value 0. It looks like these are binary data files or maybe corrupted, but certainly not empty. An empty file in vim displays as all tildes (~) in the leftmost column :-)
Try running the file filename command on the good and bad files; the latter probably says "data" due to the NUL bytes.

Bash: Too many arguments

I've coded the following script to add users from a text file. It works, but I'm getting an error that says "too many arguments"; what is the problem?
#!/bin/bash
file=users.csv
while IFS="," read USRNM DOB SCH PRG PST ENROLSTAT ; do
if [ $ENROLSTAT == Complete ] ;
then
useradd $USRNM -p $DOB
else
echo "User $USRNM is not fully enrolled"
fi
done < $file
#cat users.csv | head -n 2 | tail -n 1
Use quotes. Liberally.
if [ "$ENROLSTAT" = Complete ]
(It's a single equal sign, too.) My greatest problem in shell programming is always hidden spaces. It's one of the reasons I write so much in Perl, and why, in Perl, I tell everyone on my team to avoid the shell whenever running external programs. There is just so much power in the shell, with so many little things that can trip you up, that I avoid it where possible. (And not where not possible.)

Resources