Chapter 6 Shell Logic and Arithmetic

1.1 Doing Arithmetic in Your Shell Script

Use $(()) or let for integer arithmetic expressions

[maxwell@MaxwellDBA test]$ COUNT=$((COUNT + 5 + MAX * 2))
[maxwell@MaxwellDBA test]$ let COUNT+=5+MAX*2

 These assignment operators are also available with $(()) provided they occur inside the double parentheses.

1.2 Braching on Conditions

The if statement in bash is similar in appearance to that in other programming languages:

if [ $# -lt 3 ]
then
    printf "%b" "Error. Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 1
fi

# or alternatively:

if (( $# < 3 ))
then
    printf "%b" "Error. Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 1
fi

# a full-blown if with an elif and an else clause:

if (( $# < 3 ))
then
    printf "%b" "Error.Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit1
elif (( $# > 3 ))
then
    printf "%b" "Error. Too many arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit2
else
    printf "%b" "Argument count correct. Proceeding...\n"
fi 
[maxwell@MaxwellDBA test]$ cat trythis.sh
if ls;pwd;cd $1;
then
    echo success;
else
    echo failed;
fi
pwd
[maxwell@MaxwellDBA test]$ bash ./trythis.sh /tmp
 another.file              chmod_all2.sh   embedded_documentation   func_choose_man1.sh   nohup.out        sample          tricky.sh
 a.out                     chmod_all.sh    ext.sh                   func_choose.sh       'Oh the Waste'    select_dir.sh   trythis.sh
 asdfwednnrw2rs2esff.txt   cong.txt        file.txt                 lines                 one.file         simplest.sh     use_up_option.sh
 check_arg_count.sh        def.conf        func_choice1.sh          more.txt              quoted.sh        simpls.sh       zebra.list
 check_unset_parms.sh      donors.sh       func_choose.html         myscript.sh           readability.sh   suffixer.sh
/home/maxwell/shelllearning/test
success
/tmp
[maxwell@MaxwellDBA test]$ 

1.3 Testing for File Characteristics

Use the various file characteristic tests in the test command as part of your if statements.

[maxwell@MaxwellDBA test]$ cat checkfile.sh
#!/usr/bin/env bash
# cookbook filename: checkfile
#
DIRPLACE=/tmp
INFILE=/home/maxwell/shelllearning/test/amazing.data
OUTFILE=/home/maxwell/shelllearning/test/more.results

if [ -d "$DIRPLACE" ]
then
   cd $DIRPLACE
   if [ -e "$INFILE" ]
   then
       if [ -w "$OUTFILE" ]
       then
           doscience < "$INFILE" >> "$OUTFILE"
       else
           echo "can not write to $OUTFILE"
       fi
   else
       echo "can not read from $INFILE"
   fi
else
    echo "can not cd into $DIRPLACE"
fi
[maxwell@MaxwellDBA test]$ 

Three of them are tested using binary operators,each taking two filenames:

 

1.4 Testing for More Than One Thing

Use the operators for logical AND(-a)  and OR(-o) to combine more than one test in an expression.

if [ -r $FILE -a -w $FILE ]

# Will test to see that the file is both readable and writable.

1.5 Testing for String Characteristics

Using the single bracket if statements.

[maxwell@MaxwellDBA test]$ cat checkstr.sh
#!/usr/bin/env bash
#cookbook filename: checkstr
#
# if statement
# test a string to see if it has any length
#
# use the command line argument
VAR="$1"
#
if [ "$VAR" ]
then
    echo has text
else
    echo zero length
fi
#
if [ -z "$VAR" ]
then
    echo zero length
else
    echo has text
fi
[maxwell@MaxwellDBA test]$

1.6 Testing for Equal

The type of comparison you need determines which operator you should use.

Use the -eq operator for numeric comparisons

 The equality primary = (or ==) for string comparisons.

[maxwell@MaxwellDBA test]$ ls -ltr strvsnum.sh
-rw-rw-r-- 1 maxwell maxwell 323 Jul 26 14:46 strvsnum.sh
[maxwell@MaxwellDBA test]$ cat strvsnum.sh
#!/usr/bin/env bash
#cookbook filename: strvsnum
#
# the old string vs. numeric comparison dilemma
#
VAR1=" 05 "
VAR2="5"
printf "%s" "do they -eq as equal? "
if [ "$VAR1" -eq "$VAR2" ]
then
    echo YES
else
    echo NO
fi

printf "%s" "do they = as equal? "
if [ "$VAR1" = "$VAR2" ]
then
    echo YES
else
    echo NO
fi
[maxwell@MaxwellDBA test]$ bash strvsnum.sh
do they -eq as equal? YES
do they = as equal? NO
[maxwell@MaxwellDBA test]$ 

1.7 Testing with Pattern Matches

Use the double-bracket compound statement in an if statement to enable shell-style pattern matches on the righthand side of the equals operator:

if [[ "${MYFILENAME}" == *.jpg ]]

1.8 Testing with Regular Expressions

Use the regular expression matching of the =~ operator.Once it has matched the string. the various parts of the pattern are available in the shell variable $BASH_REMATCH.

[maxwell@MaxwellDBA test]$ cat trackmatch.sh
#!/usr/bin/env bash
# cookbook filename: trackmatch.sh
#
for CDTRACK in *
do
    if [[ "$CDTRACK" =~ "([[:alpha:][:blank:]]*)-([[:digit:]]*) - (.*)$" ]]
    then
        echo Track ${BASH_REMATCH[2]} is ${BASH_REMATCH[3]}
        mv "$CDTRACK" "Track${BASH_REMATCH[2]}"
    fi
done
[maxwell@MaxwellDBA test]$ 

1.9 Changing Behavior with Redirections

Use the test -t option in an if statement to branch between the two desired behaviors.

1.10 Looping for a While

Use the while looping construct for arithmetic conditions:

# for arithmetic conditions:

while (( COUNT < MAX ))
do
    some stuff
    let COUNT++
done

# for filesystem-related conditions:
while [ -z "$LOCKFILE" ]
do
    some things
done

# for reading input 

while read lineoftext
do
    process $lineoftext
done

1.11 Looping with a read

To clean up this directory it would be nice to get rid of all the scratch files.

# Try
svn status mysrc | grep '^?' | cut -c8- | \
    while read FN; do echo "$FN"; rm -rf "$FN"; done


# Or:

svn status mysrc | \
while read TAG FN
do 
    if [[ $TAG == \? ]]
    then
        echo $FN
        rm -rf "$FN"
    fi
done 

1.12 Loop with a Count

Use a special case of the for syntax,one that looks a lot like C language, but with double parentheses:

[maxwell@MaxwellDBA test]$ for (( i=0 ; i<10 ; i++ )); do echo $i ; done
0
1
2
3
4
5
6
7
8
9
[maxwell@MaxwellDBA test]$ for i in 1 2 3 4 5 6 7 8 9 10
> do
>   echo $i
> done
1
2
3
4
5
6
7
8
9
10
[maxwell@MaxwellDBA test]$ 

The special case of the for loop with C-like syntax is a relatively recent addition to bash. It more general from can be described as :

      for (( expr1 ; expr2 ; expr3 )) ; do list ; done

[maxwell@MaxwellDBA test]$ for (( i=0,j=0; i+j < 10 ; i++, j++ ))
> do
>    echo $((i*j))
> done
0
1
4
9
16
[maxwell@MaxwellDBA test]$ 

1.13 Looping with Floating-Point Values

The for loop with arithmetic expressions only does integer arithmetic. Use the seq command to generate your floating-point values,

[maxwell@MaxwellDBA test]$ for fp in $(seq 1.0 .01 1.1)
> do
>   echo $fp; other stuff too
> done
1.00
-bash: other: command not found
1.01
-bash: other: command not found
1.02
-bash: other: command not found
1.03
-bash: other: command not found
1.04
-bash: other: command not found
1.05
-bash: other: command not found
1.06
-bash: other: command not found
1.07
-bash: other: command not found
1.08
-bash: other: command not found
1.09
-bash: other: command not found
1.10
-bash: other: command not found
[maxwell@MaxwellDBA test]$ seq 1.0 .01 1.1 | \
> while read fp
> do
>   echo $fp; other stuff too
> done
1.00
-bash: other: command not found
1.01
-bash: other: command not found
1.02
-bash: other: command not found
1.03
-bash: other: command not found
1.04
-bash: other: command not found
1.05
-bash: other: command not found
1.06
-bash: other: command not found
1.07
-bash: other: command not found
1.08
-bash: other: command not found
1.09
-bash: other: command not found
1.10
-bash: other: command not found
[maxwell@MaxwellDBA test]$ 

1.14 Branching Many Ways

Use the case statement for a multiway branch:

case $FN in
   *.gif) gif2png $FN
       ;;
   *.png) pngOK $FN
       ;;
   *.jpg) jpg2gif $FN
       ;;
   *.tif | *.TIFF) tif2jpg $FN
       ;;
   *) printf "File not supported: %s" $FN
       ;;
esac

# This equivalent to this using if/then/else statements is 

if [[ $FN == *.gif ]]
then
    gif2png $FN
elif [[$FN == *.png ]]
then
    pngOK $FN
elif [[ $FN == *.jpg ]]
then
    jpg2gif $FN
elif [[ $FN == *.tif || $FN == *.TIFF ]]
then
    tif2jpg $FN
else
    printf "File not supported: %s" $FN
fi

1.15 Parsing Command-Line Arguments

[maxwell@MaxwellDBA test]$ cat dashes
#!/usr/bin/env bash
#cookbook filename:dashes
#
#dashes - print a line of dashes
#
#options: # How many (default 72)
#         -c X use char X instead of dashes
#
LEN=72
CHAR='-'
while (( $# > 0 ))
do
  case $1 in
     [0-9]*) LEN=$1
        ;;
     -c) shift;
        CHAR=${1:--}
        ;;
     *) printf 'usage: %s [ -c X] [#]\n' $(basename $0) >&2
        exit 2
        ;;
  esac
  shift
done
[maxwell@MaxwellDBA test]$ sh dashes -g
usage: dashes [ -c X] [#]
[maxwell@MaxwellDBA test]$ sh /home/maxwell/shelllearning/test/dashes -g
usage: dashes [ -c X] [#]
[maxwell@MaxwellDBA test]$ 

1.16 Creating Simple Menus

Use the select statement to create simple character-based screen menus.

[maxwell@MaxwellDBA test]$ cat dbinit.sh
#!/usr/bin/env bash
#cookbook filename: dbinit.sh
#
DBLIST=$(sh ./listdb | tail + 2)
select DB in $DBLIST
do
   echo Initializing database: $DB
   mysql -u user -p $DB <myinit.sql
done
[maxwell@MaxwellDBA test]$ 

1.17 Changing the Prompt on Simple Menus

The bash enviroment variable $PS3 is the prompt used by select.

#!/usr/bin/env bash
# cookbook filename: dbinit.2
#
DBLIST=$(sh ./listdb | tail +2)
PS3="0 inits >"
select DB in $DBLIST
do
 if [ $DB ]
 then
 echo Initializing database: $DB
 PS3="$((i++)) inits >"
 mysql -u user -p $DB <myinit.sql
 fi
done
$

1.18 Create a Simple RPN Calculator

Create a calculator using shell arithmetic and RPN notation:

#!/usr/bin/env bash
# cookbook filename: rpncalc
#
# simple RPN command line (integer) calculator
#
# takes the arguments and computes with them
# of the form a b op
# allow the use of x instead of *
#
# error check our argument counts:
if [ \( $# -lt 3 \) -o \( $(($# % 2)) -eq 0 \) ]
then
 echo "usage: calc number number op [ number op ] ..."
 echo "use x or '*' for multiplication"
 exit 1
fi
ANS=$(($1 ${3//x/*} $2))
shift 3
while [ $# -gt 0 ]
do
 ANS=$((ANS ${2//x/*} $1))
 shift 2
done
echo $ANS

1.19 Creating a Command-Line Calculator

[maxwell@MaxwellDBA test]$ cat fun_calc.sh
#!/usr/bin/env bash
#
# cookbook filename: func_calc
# Trivial command line calculator
function calc
{
    awk "BEGIN {print \"The answer is: \" $* }";
}
[maxwell@MaxwellDBA test]$ sh fun_calc.sh 2 + 3 + 4
[maxwell@MaxwellDBA test]$ sh -x fun_calc.sh 2 + 3 + 4
[maxwell@MaxwellDBA test]$ calc 2 + 3 + 4
-bash: calc: command not found
[maxwell@MaxwellDBA test]$ # cookbook filename: func_calc
[maxwell@MaxwellDBA test]$ # Trivial command line calculator
[maxwell@MaxwellDBA test]$ function calc
> {
>    awk "BEGIN {print \"The answer is: \" $* }";
> }
[maxwell@MaxwellDBA test]$ calc 2 + 3 + 4
The answer is: 9
[maxwell@MaxwellDBA test]$ calc 2 + 3 + 4.5
The answer is: 9.5
[maxwell@MaxwellDBA test]$ calc '(2+2-3)*4'
The answer is: 4
[maxwell@MaxwellDBA test]$ calc \(2+2-3\)\*4
The answer is: 4
[maxwell@MaxwellDBA test]$ calc '(2+2-3)*4.5'
The answer is: 4.5
[maxwell@MaxwellDBA test]$
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值