If statements in Linux terminal

Use and complete the template provided. The entire template must be completed. If you don't, your post may be deleted!

  1. The problem statement, all variables and given/known data:
    Hello all so i just started learning linux and i need to make script which compares 2 files by size and shows on the screen the bigger one but i can't figure out how to make if statement work.

  2. The attempts at a solution (include all code and scripts):

#!/bin/bash
echo "type 1st file"
read a
echo "type 2nd file"
read b
if [ stat -c %s $a > stat -c %s $b]
then
echo "$a"
else
echo "$b"
fin
  1. Complete Name of School (University), City (State), Country, Name of Professor, and Course Number (Link to Course):
    Lithuania , Vilnius , Vilniaus Collegue 1st course M.Liogys
http://eif.viko.lt/lt/page/Programu-sistemos

Two tips:

  • assign stat command output to two variables using syntax: size=`stat ...`
  • to compare those variables use -gt operator

Also take a look at: http://en.tldp.org/LDP/abs/html/refcards.html\#AEN22313

1 Like
if [ `stat -c %s $a` -gt `stat -c %s $b` ]
then
    echo "$a"
else
    echo "$b"
fi

The more modern syntax would be something like this:

if (( $(stat -c %s file1) >  $(stat -c %s file2) ))
then
    echo "$a"
else
    echo "$b"
fi
1 Like

Thanks to you both but can u explain me what

` ` 

exactly does ? Because im confused.

` ... ` or $( ... ) denote command substitution - the specified command is executed, and the resulting output used in place of the backquoted string.

In the above cases, stat is run, and the output stored in the variable size (in bartus' example) or used directly in a comparison (in fpmurphy's).

First: the "backquotes" should not be used any more. They are only there for compatibility issues but their usage is strongly discouraged. instead of `command` use

$(command)

.

Second: command substitution. Suppose you run a command "somecommand" and it produces some output - any output.

user@host:/some/where> somecommand
this is some output

You can use this output inside your own commands by using the command substitution device ("$( .... )"). The shell will first run the denoted command, replace the command substitution with its output and only then execute the rest of the line. In the example above, consider:

user@host:/some/where> echo "== $(somecommand) =="

The first step is to run "somecommand" and replace it with its output:

echo "== this is some output =="

Then, the resulting command is executed, simply displaying the original output decorated with surrounding equal-signs.

This example is not doing something impressive, but in fpmurphy's case it dealt with a possibly varying command output. This line:

if (( $(stat -c %s file1) >  $(stat -c %s file2) ))

boils down to:

if (( 5 > 4 ))

or something such, depending on what "stat -c %s <filename>" would yield.

Btw.: you might notice a slight flaw in your programs logic. What would happen if the two files are of absolutely equal size? The solution is left to the reader, but a hint may be in order: "if"-statements can be nested.

I hope this helps.

bakunin

First time i see constantly used the ( for if statements, i'm used to [..

Regard 'if statements'...
[[ condition ]] && echo succeeded || echo failed

Example:
[[ -z $XDG_DESKTOP_DIR ]] && echo "Your desktop is: $XDG_DESKTOP_DIR" || echo "$HOME/.config/user-dirs.dirs not loaded yet."

Which is the same as: (note the '\', that tells the line isnt dont yet, there must be no trailing spaces!)

[[ -z $XDG_DESKTOP_DIR ]] && \
    echo "Your desktop is: $XDG_DESKTOP_DIR" || \
    echo "$HOME/.config/user-dirs.dirs not loaded yet."

Which i prefer for 'short code' like setting a variable.

The && is appending the following command if previous command returns 0/true.
The || indicates what is done if the previous condition/command failed.

Examples:

[[ ! 0 -eq $UID ]] && echo "You're not root, and we abort" && exit
[[ 0 -eq $UID ]] || echo "You're not root, but we continue anyway"
[[ 0 -eq $UID ]] && echo "Must not be root!" && exit || echo "You may pass $USER"

hth

To explain that i have to dig into UNIX history somewhat:

First: The general form of the if -statement in Bourne-descendant shells (ksh, bash, [POSIX-]sh, etc.) is:

if command ; then

Which branch of the if -statement (the "if"- or the "else"-branch) is executed is decided by examining the return code (error level) of the command. The following lines will do absolutely the same, but the latter is preferable because it saves on fork()-calls:

/some/command
if [ $? -eq 0 ] ; then
if /some/command ; then

What is now if [ .... ] , you might ask.

Because of the mechanism of if the UNIX designers came up with a clever utility: test . This command executes all sorts of comparisons and sets its return code according to the result of these comparison. If you wanted to branch on two variables being equal you could do (i have marked bold the test-command and its parameters):

if /usr/bin/test $a -eq $b ; then

Now, this looked a bit unhandy. Therefore a further trick was to create a link /usr/bin/[ to /usr/bin/test , the line would now look like:

if [ $a -eq $b ; then

But this still was not completely satisfactory, because programmers are religiously raised to close what they open: quotes, brackets, braces, clauses, ....

Therefore, the last twist was to create /usr/bin/[ as a program in its own right which works just like /usr/bin/test but requires a "]" as the last parameter. Now the code as we know it were possible:

if [ $a -eq $b ] ; then

Notice, though, that "[" is a command and "]" is one of its parameters. Therefore, the following are all syntactically wrong (for obvious reasons):

if [$a -eq $b ] ; then
if[ $a -eq $b ] ; then
if [ $a -eq $b] ; then

OK, this is all good, but what is if [[ ... then?

In fact "[[" is the same as "[", but as a shell-built-in instead of an external command. Shell developers found out that test and its companion [ were used so oftenly that they built it into their shells to save on system calls.

Lastly, what is if (( ... )) now?

Well, the same as i wrote above: if command , where command is a device in ksh as well as bash: you can do integer math surrounded by double rounded brackets:

(( x += 1 ))

is a legal command and the same as (in fact a substitution for) the (quite old-fashioned) built-in let :

let x=x+1

Like let also (( ... )) has a return code and this is what if acts upon.

I hope this clears it up a bit.

bakunin

1 Like

Right, personal experience showed me that the use of [[ condition ]] is the most compatible one among shells.
But then again i only use sh and bash on diffrent linux'...

man bash says:

       ((expression))
              The expression is evaluated according to the rules described below under ARITHMETIC EVALUATION.  If the value of the expression is non-zero, the return status is 0;  otherwise  the
              return status is 1.  This is exactly equivalent to let "expression".

       [[ expression ]]
              Return a status of 0 or 1 depending on the evaluation of the conditional expression expression.  Expressions are composed of the primaries described below under CONDITIONAL EXPRES-
              SIONS.  Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command
              substitution, process substitution, and quote removal are performed.  Conditional operators such as -f must be unquoted to be recognized as primaries.

              When used with [[, the < and > operators sort lexicographically using the current locale.

              When  the  ==  and != operators are used, the string to the right of the operator is considered a pattern and matched according to the rules described below under Pattern Matching.
              If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters.  The return value is 0 if the string matches  (==)  or  does
              not match (!=) the pattern, and 1 otherwise.  Any part of the pattern may be quoted to force it to be matched as a string.

              An  additional binary operator, =~, is available, with the same precedence as == and !=.  When it is used, the string to the right of the operator is considered an extended regular
              expression and matched accordingly (as in regex(3)).  The return value is 0 if the string matches the pattern, and 1 otherwise.  If the regular expression is  syntactically  incor-
              rect,  the conditional expression's return value is 2.  If the shell option nocasematch is enabled, the match is performed without regard to the case of alphabetic characters.  Any
              part of the pattern may be quoted to force it to be matched as a string.  Substrings matched by parenthesized subexpressions within the regular expression are saved  in  the  array
              variable  BASH_REMATCH.   The element of BASH_REMATCH with index 0 is the portion of the string matching the entire regular expression.  The element of BASH_REMATCH with index n is
              the portion of the string matching the nth parenthesized subexpression.

              Expressions may be combined using the following operators, listed in decreasing order of precedence:

              ( expression )
                     Returns the value of expression.  This may be used to override the normal precedence of operators.
              ! expression
                     True if expression is false.
              expression1 && expression2
                     True if both expression1 and expression2 are true.
              expression1 || expression2
                     True if either expression1 or expression2 is true.

              The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression.

This is exactly what i said. I have marked bold the relevant part pertinent to "(( ... ))" and for "[[ ... ]]" have a look at what man test has to say about test s behavior.

I hope this helps.

bakunin