username="hello"
password="3333"
function login {
# 1 - Username
# 2 - Password
match=0
cat LoginsMaintMenu.txt | while read line; do
x=`echo $line | awk '{print $1}'`
y=`echo $line | awk '{print $2}'`
if [ "${x}" == "${1}" ] && [ "${y}" == "${2}" ]; then
echo "match"
match=1
echo $match
break
fi
done
echo $match
return $match
}
echo $username $password
login ${username} ${password}
if [ $? -eq 0 ]; then
echo "FAIL"
else
echo "success"
fi
output:
hello 3333
match
1
0
FAIL
THE PROBLEM:
I don't understand why it is echoing "fail". the "match" variable gets set to 1 inside the while loop, but for some reason once I am out of the while loop it still thinks it is the initial zero from its declaration.
I have tried doing a lot of different things, so if someone could give me something concrete to try that'd be great!
Thanks
The reason that this is not working is actually the UUOC. In bash, the right side of a pipeline is ran inside of a sub-shell. Any variables set inside of a sub shell will not be set in the parent shell. To fix this, use redirection instead of a pipeline:
username="hello"
password="3333"
function login {
# 1 - Username
# 2 - Password
match=0
while read x y _; do
if [ "${x}" == "${1}" ] && [ "${y}" == "${2}" ]; then
echo "match"
match=1
echo $match
break
fi
done < LoginsMaintMenu.txt
echo $match
return $match
}
echo $username $password
if login "${username}" "${password}"; then
echo "FAIL"
else
echo "success"
fi
The while read ... part of your code (that gets its input from the cat pipe) runs in a subshell. Changes to variables inside that are not visible outside that subshell.
To work around that, change your loop to:
while read ... ; do
...
done < LoginsMaintMenu.txt
Related
#!/bin/bash
host=$1
startport=$2
stopport=$3
function pingcheck
{
ping = `ping -c 1 $host | grep bytes | wc -l`
if [ $ping > 1 ]; then
echo "$host is up";
else
echo "$host is down quitting";
exit
fi
}
function portcheck
{
for ((counter=$startport; counter<=$stopport; counter++))
do
(echo > /dev/tcp/$host/$counter) > /dev/null 2>&1 && echo "$counter open"
done
}
pingcheck
portcheck
I tried testing the script by passing 127.0.0.1 1 5 to it from the terminal but all i keep getting is ping: unknown host =
127.0.0.1 is down quitting. Tried with other IP Addresses as well, I got the same output. I was following instruction from a book as I am new to shell scripting. It will be helpful if someone can tell me what I am doing wrong.
I made some comments inline:
#!/bin/bash
host=$1
startport=$2
stopport=$3
function pingcheck
{
ping=`ping -c 1 $host | grep bytes | wc -l` #Don't use spaces before and after the "="
if [ $ping -gt 1 ]; then #Don't use >, use -gt
# if [[ $ping > 1 ]]; then #Or use [[ and ]], but this won't work in all shells
echo "$host is up";
else
echo "$host is down quitting";
exit
fi
}
function portcheck
{
for ((counter=$startport; counter<=$stopport; counter++))
do
(echo > /dev/tcp/$host/$counter) > /dev/null 2>&1 && echo "$counter open"
done
}
pingcheck
portcheck
Variables in bash are always in the format:
VARNAME=VALUE
You should not put spaces in between there. VALUE could be an expression using `` or using $(). $() is usually the preferred way, because you can do $(something $(something)) and you can't do `something `something``.
The syntax of if is:
if EXPRESSION
then
something
fi
An expression is in sh always a call to an application. [ is an application usually used in ifs. You can get a really good manual of [ by doing man [. Bash has native support for [[, which isn't an application, but can do more than [.
GOAL: My goal in this assignment is to create a script that will take in a student id as an input and will output a matching student's name OR an error message saying there is none by that name in this class. Im fairly new to Linux and it is kinda tough for me but I would love all the help I can get. Thanks!
Screenshot Page 1 of assignment
Screenshot Page 2 of assignment
My script is printing off everyones name in the file rather than just the one I am searching for.
#!/bin/bash
# findName.sh
searchFile="/acct/common/CSCE215-Fall17"
if [[ $1 = "" ]] ; then
echo "Sorry that person is not in CSCE215 this semester"
exit 2
fi
while read LINE
do
firstNameIndex=0
middleNameIndex=1
lastNameIndex=2
userIDIndex=3
IFS=', ' read -r -a lineArray <<< "$LINE"
if [[ $1 -eq ${lineArray[$userIDIndex]} ]] ; then
echo ${lineArray[$firstNameIndex]} ${lineArray[$middleNameIndex]} ${lineArray[$lastNameIndex]}
fi
done < "$searchFile"
VERSION 3:
Here is how I would do it with grep. This prevents you from looping through the input file.
#!/bin/bash
searchFile="sample.txt"
function notincourse()
{
echo "Sorry that person is not in CSCE215 this semester"
exit 2
}
# Verify arguments, 1 argument, name to search for
if [ $# -ne 1 ]
then
echo "findName.sh <NAME>"
exit 1
else
searchfor=$1
fi
# Verify if the name is in the file
nameline=$(grep $searchfor $searchFile)
#if [ $(echo $nameline | wc -l) -eq 0 ]
if [ $? -eq 1 ]
then
notincourse
else
idvalue=$(echo $nameline | cut -d',' -f1)
if [ "$idvalue" == "$searchfor" ]
then
IFS=', ' read -r -a lineArray <<< "$nameline"
echo ${lineArray[1]} ${lineArray[2]} ${lineArray[3]}
else
notincourse
fi
fi
I tried if with the following test input file:
111, firstname1, middlename1, lastname1
222, firstname2, middlename2, lastname2
333, firstname3, middlename3, lastname3
VERSION 3: it now verifies that the id is indeed the first word in the line. I realized that if the student id is someown included in his name (ya, but better safe than sorry!) my grep would return true!
One line of code to change:
if [[ "$1" == "${lineArray[$userIDIndex]}" ]] ; then
I am writing a script to pass commands to a console and redirect the output to a log for analysis. This is the script I have now.
#!/bin/ksh
gg_sci(){
$GG_HOME/ggsci <<EOF > /home/org/obey.log
obey /home/org/mon.oby
EOF
}
check_st(){
status=`cat obey.log | grep -i $1 | awk '$2!=""{print $2}'`
echo $status
if [ $status -eq "RUNNING" ]
then
echo "GG process $1 is running"
exit 0
}
gg_sci
check_st test
This script works if I put the 2 functions into 2 different scripts. When I put them into one script, I get an error
ksh: 0403-057 Syntax error: `}' is not expected.
After debugging, I've determined the EOF is reading in the } that closes the function. I'm not sure what I'm doing wrong, the EOF function works correctly if that's the only thing in the script.
You're missing a fi to close your if.
Also, -eq is used to check for numeric equality, to compare strings use =:
check_st(){
status=`cat obey.log | grep -i $1 | awk '$2!=""{print $2}'`
echo "$status"
if [ "$status" = "RUNNING" ]
then
echo "GG process $1 is running"
exit 0
fi
}
I have a variable which i am trying to set something like this:
#!/bin/sh
found=0
id=1
echo "Hello" |
while [ $id != 5 ]
do
id=`expr $id + 1`
echo $id
found=1
done
echo "found = $found" // I expect this to be 1
Why, and how to set this value?
I am forced to use like this (piped), because the actual code in production environment is:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
echo "select file_system_id, mount_name from SystemTable" | mysql ifm -uroot -pinsite3 |
while read file_system_id mount_name
do
if [ "$id" == "$file_system_id" -a "$my_mount_name" == "$mount_name" ]; then
echo "Match found for file system ID and mount name"
found=1
fi
done
echo "found = $found" // I expect this to be 1, when a match, but does not
The pipe runs in a subshell. You can do a few things to make it work, the simplest is:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
echo "select file_system_id, mount_name from SystemTable" |
mysql ifm -uroot -pinsite3 | {
while read file_system_id mount_name
do
if [ "$id" == "$file_system_id" -a "$my_mount_name" == "$mount_name" ]; then
echo "Match found for file system ID and mount name"
found=1
fi
done
echo "found = $found"; }
# Note the enclosing {}. Inside the black, the variable $found is set.
# After this comment, it will be zero.
This technique may require that the enclosing block be fairly large, so you may want to refactor the rest of the script to make this usable. Another option is to use a fifo or to put the echo/mysql pipeline into a process substitution. (The latter is not portable, but works in bash which may be adequate.) However, in this particular case, it is probably better to do something like:
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
echo "select file_system_id, mount_name from SystemTable" |
mysql ifm -uroot -pinsite3 | {
while read file_system_id mount_name
do
if [ "$id" == "$file_system_id" -a "$my_mount_name" == "$mount_name" ]; then
echo "Match found for file system ID and mount name"
exit 0 # Exit the subshell succesfully
fi
done
exit 1; } && found=1
You can pass the variables to the sub shell's environemnt:
foo=1
bar=2
echo "sds" | foo="$foo" bar="$bar" while ...
As #fedorqui commented, bash puts pipeline components in separate subshells, so the changes to your variables disappear when the subshell exits.
There are 2 strategies to deal with this:
only use the changed variables in the same subshell
echo "Hello" |
{
while [ $id != 5 ]
do
((id++))
echo $id
found=1
done
echo "found = $found" // I expect this to be 1
}
This can be a problem if you have lots of code that relies on those variables
replace the pipeline with process substitution. This means that the while loop is not executed in a subshell, it's run in the current shell:
while [ $id != 5 ]
do
((id++))
echo $id
found=1
done < <(echo "Hello")
echo "found = $found" // I expect this to be 1
This can suffer from poor readability, but you can put as many newlines inside <(...) as you want.
Your production code rewritten with process substitution (and bash/ksh conditional syntax):
found=0
id=1
my_mount_name="/opt/insiteone/fuse-mount"
while read file_system_id mount_name; do
if [[ $id == $file_system_id ]] && [[ $my_mount_name == $mount_name ]]; then
echo "Match found for file system ID and mount name"
found=1
fi
done < <(
echo "select file_system_id, mount_name from SystemTable" |
mysql ifm -uroot -pinsite3
)
echo "found = $found"
i=0
EDA="xx7p2"
while read line
do
echo "i is --- $i"
echo " PACKAGE IS - --$EDA--"
#echo $line "\n"
if (( $i > 0 ))
then
package=$(echo $line | awk '{print $1}')
echo "EDA PACKAGE IN LOOP IS ---$Eda_package---"
if [ "$package" == "$EDA" ] ; then
#then
well_bias=$(echo $line | awk '{print $2}')
biasmap=$(echo $line | awk '{print $3}')
unified=$(echo $line | awk '{print $4}')
echo "eda pack --$package bias is --$wel biasmap is --$biasmap unified- --$unified"
fi
fi
i=$((i+1))
done < config.list
Here the statements inside the second if statement is not executed even if the two variables are same. Am I missing something here?
Make a simplified version of your problem to get it nailed down.
I can't reproduce your problem with this sample script:
#!/bin/bash
i=$1
a=$2
while read line
do
if (( $i > 0 ))
then
echo "1st if "+$i
if [ "$a" == "foo" ] ; then
echo "2nd if"
fi
fi
i=$((i+1))
done < nfoo.sh
called nfoo.sh and calling it ./nfoo.sh 4 bar, ./nfoo.sh -4 bar, ./nfoo.sh 4 foo and ./nfoo.sh -4 foo.
Might your error be in the package-assignement? You don't need awk for such a simple task. For a single word, to just extract the first word, you would use echo ${line/ */} while I see nothing wrong in your awk-statement.
Since you extract more arguments, I would suggest an array:
#!/bin/bash
i=$1
a=$2
while read line
do
if (( $i > 0 ))
then
arr=($line)
echo "1st if "+$i
if [ "if" == "${arr[0]}" ] ; then
echo "2nd if: " $line
fi
fi
i=$((i+1))
done < nfoo.sh
Btw.: Where is the else, the headline is talking about?
UPDATE: based on more testing with the small script below:
Having the $ as part of the string in package variable was a problem for me. If I escape it with a \$ I get it to work with the correct comparison operator mentioned below.
Use this for comparison (note the space before/after the =)
if [ "$package" = "$EDA" ] ; then
Without the space the expression seems to evaluate always to true. (Also, as an aside, using == without spaces before/after will result in an [: 11: $EDAx: unexpected operator)
I used this small script for testing, you can use to verify your own constructs, hope it's helpful. This works correctly as shown
#!/bin/bash
package="\$EDA"
echo $package
if [ "$package" = "\$EDA" ] ; then
echo "The same"
else
echo "Not the same"
fi
Note1: I added the else to be certain of the outcome of the comparison, as your script doesn't contain any else
Note2: It's always better to explicitly specify what shell to run rather than to depend on some external implicit environment settings, so I would recommend you add the #!/bin/bash to your script, it certainly won't hurt.
Other Comparison Operator from the Advanced Bash-Scripting Guide shows:
string comparison
=
is equal to
if [ "$a" = "$b" ]
Note the whitespace framing the =.
if [ "$a"="$b" ] is not equivalent to the above.
== is equal to
if [ "$a" == "$b" ]
This is a synonym for =.