Bash scripting using an exit status in an if statement - linux

May be a novice question but anyways in my intro to linux/unix class were touching on bash scripting and in one of the problems I got the it tasked me with making a script so if the user searched to a name in a file that wasn't there it would output a messaged saying 'your_input is not in the directory'
It says to use if statements and the exit status $?.
So far I got the input portion but I'm not sure how to properly use the $? in a if statement if its possible.
#!/bin/bash
name=$1
if [ "$name" = "" ]
then echo -n "Enter a name to search for: "
read name
fi
grep -i $name ~uli101/2014c/phonebook
if [ "$?" < "0" ]
then echo "error"
fi
I get the error:
./phone4: line 14: 0: No such file or directory
My question is: How can I use the $? with and if statement, and If I can't, can you explain me how to use the $? in this problem?
Note: I did use echo $? to see how $? gave a 0 if grep worked and a 1 if it didn't.

There's two bugs in it. The one you already see is that in the [] expression, the < is interpreted not as "less than" but as stream redirection operator. The reason is that [ is just another program (an alias for test), so [ "$?" < "0" ] is similar to cat < filename. The other error is that you don't want to check for "less than" but for "not equal". In sum:
if [ "$?" < "0" ]
should be
if [ "$?" -ne "0" ]
Or you could write
if ! grep "$name" ~uli101/2014c/phonebook
...because if interprets a return code of zero as true and everything else as false.

never mind one of my friends pushed me in the right direction:
all I had to do is:
if [ "$?" = "1" ]
then echo "error"
fi
pretty much I was over thinking it, I just needed to say if $? = 1 then error, because in the readings it said $? can be greater then 1 I was trying to compensate for that.

It should be
if [ "$?" -gt 0 ]
The symbol '<' is a redirection operator, and it's not a Python or C - everything in a shell script is a command, including the text after 'if', and you are executing a command named '[' here, you may find it at the location /usr/bin/[, and this command uses -gt and -lt parameters to compare numbers, instead of '>' and '<', which are special shell operators.
You can rewrite this code like this:
if grep -i "$name" ~uli101/2014c/phonebook
then true # 'true' is also a command, which does nothing and returns success
else echo "Error"
fi
or even like this, using '||' operator, which will execute following command only if previous command returned an error:
grep -i "$name" ~uli101/2014c/phonebook || echo "Error"

The "$?" doesn't need quotes, as it is a number really. If you want better script, check on existance of the Phonebook file, and exit before asking the Name input if the file is missing. Also, if you reply nothing (enter only) on the READ command, you may need to do something.
#!/bin/bash
name=$1
phonebook=~/phonebook
if [ "$name" = "" ]
then
echo -n "Enter a name to search for: "
read name
fi
grep -i "$name" $phonebook
if [ $? -gt 0 ]
then
echo "error, no \"$name\" in $phonebook"
fi

Related

Bash script that allows one word as user input

Made a script that the user gives a "parameter" and it prints out if it is a file, directory or non of them. This is it :
#!/bin/bash
read parametros
for filename in *
do
if [ -f "$parametros" ];
then
echo "$parametros is a file"
elif [ -d "$parametros" ];
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
exit
done
Altough i want the user to be allowed to give only one word as a parameter. How do i make this happen ? (For example if user press space after first word there would be an error message showing "wrong input")
#!/bin/bash
read parametros
if [[ "$parametros" = *[[:space:]]* ]]
then
echo "wrong input"
elif [[ -f "$parametros" ]]
then
echo "$parametros is a file"
elif [[ -d "$parametros" ]]
then
echo "$parametros is a directory"
else
echo " There is not such file or directory"
fi
See http://mywiki.wooledge.org/BashFAQ/031 for the difference between [...] and [[...]].
You have to use the $#. It gives the number of the parameters.
The code will be something like:
if [ "$#" -ne 1 ]; then
printf 'ERROR!\n'
exit 1
fi
First, I'm curious why you want to restrict to one word - a file or directory could have spaces in it, but maybe you are preventing that somehow in your context.
Here are a few ways you could approach it:
Validate the input after they enter it - check if it has any spaces, eg: if [[ "parametros" == *" " ]]; then...
Get one character at a time in a while loop, eg with: read -n1 char
Show an error if it's a space
Break the loop if it's 'enter'
Build up the overall string from the entered characters
1 is obviously much simpler, but maybe 2 is worth the effort for the instant feedback that you are hoping for?

What is -z in bash

I am trying to understand the following code:
if [ -z "$1" ] || [ -z "$2" || [ "${3:-}" ]
then
echo "Usage: $0 <username> <password>" >&2
exit 1
fi
I want to understand what we mean by -z "$1" and "${3:-}" in the code.
Please also help me understand >&2 in the code.
1) Your code is not correct, you missed one ] bracket somewhere. Probably after [ -z "$2" block.
2) if statement executes following command(s) and then executes block of code enclosed in then .. fi or then .. else keywords if the return value of the command(s) is true (their exit code is 0)
3) [ is just an alias for the test command (try man test). This command takes several parameters and evaluates them. For example, used with -z "$something" flags would return true (0) if $something is not set or is an empty string. Try it:
if [ -z "$variable" ]; then
echo Variable is not set or is an empty string
fi
4) || statement is an OR. Next command would be executed if the previous one returned false statement. So in the statement
if [ -z "$variable" ] || [ -z "$variable2" ]; then
echo Variable 1 or variable 2 is not set or is an empty string
fi
command [ -z "$variable2" ] would be executed only if variable was empty. The same could be achieved with different syntax:
if [ -z "$variable" -o -z "$variable2" ]; then
echo Variable 1 or variable 2 is not set or is an empty string
fi
which should be faster, because it requires only one instance of the test program to be run. Flag -o means OR, so you could read it as:
If variable is not set/empty OR variable2 is not set/EMPTY...
5) Statement "[ ${3:-} ]" means return true if $3 (the third argument of the script) is set.
6) >&2 is a stream redirection. Every process has two outputs: standard output and error output. These are independent and could be redirected (for example) to be written to two different files. >&2 means "redirect standard output to the same location as standard error".
So to sum up: commands between then .. fi will be executed IF the script is run with $1 empty or $2 empty or $3 NOT empty That means that the script should be run with exactly two parameters. And if not, the echo message will be printed to standard error output.
-z STRING means the length of STRING is zero.
${parameter:-word} If parameter is unset or null, the expansion of word is substituted. In your case $3 is just set with a blank value, if $3 do not have any value.
&2 writes to standard-error. I mean the stdout value of the executed command is sent to stderr,

bash check for empty string/line using -z

I am relatively new to bash scripting, and I have the following script, which is not giving me results I expect. So, my script looks like so:
#!/bin/bash
echo "Today is $(date)"
shopt -s nullglob
FILES=/some/empty/dir/with/no/text/files/*.txt
#echo $FILES
if [ -z "$FILES" ]
then
echo 'FILES variable is empty'
exit
else
echo 'FILES variable is not empty'
echo 'done' > write_file_out.dat
fi
So, the directory I am trying to use FILES on is completely empty - and still, when I do if [ -z "$FILES" ] it seems to say that it is not empty.
Baffled by this - wondering if someone can point me in the right direction.
Instead of:
FILES=/some/empty/dir/with/no/text/files/*.txt
You need to use:
FILES="$(echo /some/empty/dir/with/no/text/files/*.txt)"
Otherwise $FILES will be set to: /some/empty/dir/with/no/text/files/*.txt and this condition [ -z "$FILES" ] will always be false (not empty).
You can also use BASH arrays for shell expansion:
FILES=(/some/empty/dir/with/no/text/files/*.txt)
And check for:
[[ ${#FILES[#]} == 0 ]]
for empty check.

Delimiter “, white spaces and bash script in Linux

I want in a bash script (Linux) to check, if two files are identical.
I use the following code:
#!/bin/bash
…
…
differ=$(diff $FILENAME.out_ok $FILENAME.out)
echo "******************"
echo $differ
echo "******************"
if [ $differ=="" ]
then
echo "pass"
else
echo "Error ! different output"
echo $differ
fi
The problem:
the diff command return white space and break the if command
output
******************
82c82 < ---------------------- --- > ---------------------
******************
./test.sh: line 32: [: too many arguments
Error ! different output
The correct tool for checking whether two files are identical is cmp.
if cmp -s $FILENAME.out_ok $FILENAME.out
then : They are the same
else : They are different
fi
Or, in this context:
if cmp -s $FILENAME.out_ok $FILENAME.out
then
echo "pass"
else
echo "Error ! different output"
diff $FILENAME.out_ok $FILENAME.out
fi
If you want to use the diff program, then double quote your variable (and use spaces around the arguments to the [ command):
if [ -z "$differ" ]
then
echo "pass"
else
echo "Error ! different output"
echo "$differ"
fi
Note that you need to double quote the variable when you echo it to ensure that newlines etc are preserved in the output; if you don't, everything is mushed onto a single line.
Or use the [[ test:
if [[ "$differ" == "" ]]
then
echo "pass"
else
echo "Error ! different output"
echo "$differ"
fi
Here, the quotes are not strictly necessary around the variable in the condition, but old school shell scripters like me would put them there automatically and harmlessly. Roughly, if the variable might contain spaces and the spaces matter, it should be double quoted. I don't see a need to learn a special case for the [[ command when it works fine with double quotes too.
Instead of:
if [ $differ=="" ]
Use:
if [[ $differ == "" ]]
Better to use modern [[ and ]] instead of an external program /bin/[
Also use diff -b to compare 2 files while ignoring white spaces
#anubhava answer is correct,
you can also use
if [ "$differ" == "" ]

Multiple conditions in ShellScripting

This is my Shellscript
echo "IsInteractive"
read IsInteractive
if [ "$IsInteractive" == "true" ]; then
echo "Name"
read name
echo "Password"
read password
if [ "$name" == "abcd" & "$password" == "pwd" ]; then
echo "correct username and password"
else
echo "wrong username or password"
fi
elif [ "$IsInteractive" == "false" ]; then
echo "Everything working fine.But no logic given yet"
else
echo "Give proper input"
fi
Is there something wrong in the 2nd if-condition?I tried putting && in the condition,but didn't work
You don't use multiple condition inside square brackets as &, you use -a. Or you use multiple brackets if [ $a = "a" ] && [ $b = "c" ]
You can also use the case/esac construct , eg
case "$name$password" in
"abcdpwd" ) echo "correct" ;;
*) echo "not correct";;
esac
This is much cleaner than if/else IMO.
Inside square brackets -a is the equivalent to &&
Also, you should probably be using = not ==. Read the manpage for your shell.
if [ "$name" == "abcd" -a "$password" == "pwd" ]; then echo true; else echo false; fi
This and MANY more "basic" questions can be answered quickly and without the need for a forum-post with the command man bash on most systems; and if it's not there just google "man bash" and pick the one which seems closest to your system... they're all "pretty much the same", especially at the basic level.
Cheers. Keith.
EDIT: FWW: the [ ] construct is a short-cut for "test", a function which is built-into all the the "standard" shells (sh, csh, ksh, and bash)... so the following code is EXACTLY equivalent:
$ a=a
$ b=c
$ if test "$a" = "a" && test "$b" = "c"; then echo true; else echo false; fi
true
The if then construct just evaluates the return value from the test function. You can display the return value of your last shell command with $?... but beware, echo also sets $?:
$ true
$ echo $?
0
$ false
$ echo $?
1
$ echo $?
0
The really interesting ramification of that is that the if then construct can evaluate anything which returns success=0=true or failure=anything BUT 0 (typically 1=false)... be that a shell built-in function, a user-defined function, a unix utility or a program you wrote yourself. Hence the following code is roughly equivalent:
$ if echo "$a:$b" | fgrep -s "a:c"; then echo true; else echo false; fi
a:c
true
NOTE: looks like my system's fgrep doesn't accept the -s for silent switch. Sigh.
Note that in above example, where the output from echo is being piped to the standard fgrep utility, it is the return value of fgrep (the LAST command to be invoked) which is evaluated by if then.
Good luck, and may root be with you. Cheers again. Keith.
A minor change will resolve this scripting error [: missing `]'.
At line 8 replace '&' with '-a'
-a, the logical AND. If both the operands are true then condition would be true otherwise it would be false
Working code below
echo "IsInteractive"
read IsInteractive
if [ "$IsInteractive" == "true" ]; then
echo "Name"
read name
echo "Password"
read password
if [ "$name" == "abcd" -a "$password" == "pwd" ]; then
echo "correct username and password"
else
echo "wrong username or password"
fi
elif [ "$IsInteractive" == "false" ]; then
echo "Everything working fine.But no logic given yet"
else
echo "Give proper input"
fi

Resources