Shell

Shell Types

  • Bourne Shell(/usr/bin/sh or /bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

Usually, we not distinct Bourne Shell and Bourne Again Shell

Shell zh_CN

Shell zh_CN

create->edit: vi edit->run: ./ run->why:?

Create hello.sh

houbinbindeMacBook-Pro:shell houbinbin$ pwd
/Users/houbinbin/code/shell
houbinbindeMacBook-Pro:shell houbinbin$ vi hello.sh

Edit the content of hello.sh

#!/bin/bash
echo "hello world!"
  • run the hello.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh hello.sh
hello world!
  • another way to run
houbinbindeMacBook-Pro:shell houbinbin$ ./hello.sh
-bash: ./hello.sh: Permission denied
houbinbindeMacBook-Pro:shell houbinbin$ chmod +x ./hello.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./hello.sh
hello world!

mean of hello.sh

#! tells OS which Interpreter to use, echo to print info in window.

read from input

  • hello_name.sh
#!/bin/bash

# Author:houbinbin

echo "Please enter your name?"
read NAME
echo "Hello, $NAME!"
  • run
houbinbindeMacBook-Pro:shell houbinbin$ vi hello_name.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh hello_name.sh
Please enter your name?
houbinbin
Hello, houbinbin!
houbinbindeMacBook-Pro:shell houbinbin$

Shell Var

Title: Shell Var Define->ReDefine: ReDefine->Use: Use->Remove:

Define

  • No Blank between var name and =

  • Start with [a-zA-Z], name can with _

  • No punctuation mark and no key word

my_name="houbinbin"

Redefine

A defined var can be re-defined

my_name="houbinbin"
my_name="ryo"

Use

  • use_var.sh
my_name="houbinbin"
echo $my_name
  • run
houbinbindeMacBook-Pro:shell houbinbin$ vi use_var.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh use_var.sh
houbinbin

ReadOnly

A readonly var can’t be change.

  • readonly_var.sh
# !/bin/bash

my_name="houbinbin"
readonly my_name

my_name="new name"
  • run
houbinbindeMacBook-Pro:shell houbinbin$ vi readonly_var.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh readonly_var.sh
readonly_var.sh: line 4: my_name: readonly variable

Remove

Use unset to remove define var.

  • unset_var.sh
#!/bin/bash

my_name="ryo"
unset my_name
echo ${my_name}
  • run
houbinbindeMacBook-Pro:shell houbinbin$ vi unset_var.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh unset_var.sh

houbinbindeMacBook-Pro:shell houbinbin$

Special Var

Command Desc
$0 当前脚本的文件名
$n 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。
$# 传递给脚本或函数的参数个数。
$* 传递给脚本或函数的所有参数。
$@ 传递给脚本或函数的所有参数。被双引号(“ “)包含时,与 $* 稍有不同,下面将会讲到。
$? 上个命令的退出状态,或函数的返回值。
$$ 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。
  • special_var.sh
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"
  • run
houbinbindeMacBook-Pro:shell houbinbin$ vi special_var.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh special_var.sh hello world my
File Name: special_var.sh
First Parameter : hello
First Parameter : world
Quoted Values: hello world my
Quoted Values: hello world my
Total Number of Parameters : 3

$* and $@

$*$@ 都表示传递给函数或脚本的所有参数,不被""包含时,都以”$1” “$2” … “$n” 的形式输出所有参数。

但是当它们被""包含时,$* 会将所有的参数作为一个整体,以”$1 $2 … $n”的形式输出所有参数;$@ 会将各个参数分开,以”$1” “$2” … “$n” 的形式输出所有参数。

  • diff_demo.sh
#!/bin/bash

# Author:houbinbin

echo "display of \$* "

for i in "$*";
do
    echo $i
done

echo "display of \$@ "
for i in "$@";
do
    echo $i
done
  • run
houbinbindeMacBook-Pro:shell houbinbin$ vi diff_demo.sh
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh diff_demo.sh 1 2 3 4
display of $*
1 2 3 4
display of $@
1
2
3
4
houbinbindeMacBook-Pro:shell houbinbin$

Shell Array

Title: Shell Array Define->Read: Read->Read All:

Define

Shell only support single-dimensional arrays.

array=(value1 value2 ... valuen)
  • array.sh
#!/bin/sh

# array demo
array=(a b "c" d)

# another way to define array

array_two[0]=a
array_two[1]=b
array_two[2]="c"
array_two[3]=d

Read

You can read from array like this:

${array_name[index]}
  • read_array.sh
#!/bin/sh

# read from array

array=(a b c "d")
echo "First elem is ${array[0]}"
echo "Second elem is ${array[1]}"
echo "Third elem is ${array[2]}"
echo "Last elem is ${array[-1]}"
  • run
root@iZuf60ahcky4k4nfv470juZ:~/code/shell# chmod +x read_array.sh 
root@iZuf60ahcky4k4nfv470juZ:~/code/shell# ./read_array.sh 
First elem is a
Second elem is b
Third elem is c
Last elem is d

Read all elem

We can use * or @ to get all elem in array.

  • read_all_array.sh
#!/bin/sh
# Read all elem in array

array=(a b c d)
echo "All elem in array: ${array[*]}"
echo "All elem in array: ${array[@]}"
  • run
root@iZuf60ahcky4k4nfv470juZ:~/code/shell# chmod +x read_all_array.sh 
root@iZuf60ahcky4k4nfv470juZ:~/code/shell# ./read_all_array.sh 
All elem in array: a b c d
All elem in array: a b c d

Array Length

We can use ${#array[*]} or ${#array[@]}, to get the array size.

  • array_length.sh
!#/bin/sh
# array length

array=(a b c d E)
echo "the size of array is: ${#array[*]}"
echo "the size of array is: ${#array[@]}"
  • run
root@iZuf60ahcky4k4nfv470juZ:~/code/shell# chmod +x array_length.sh 
root@iZuf60ahcky4k4nfv470juZ:~/code/shell# ./array_length.sh 
the size of array is: 5
the size of array is: 5

Operator

The original bash not support math oper, we can use expr instead.

Attention:

1.expr is in `, not

2.expr between numbers should split with blank.

  • num_oper.sh
#!/bin/bash

# num oper

value1=10
value2=20
sum=`expr $value1 + $value2`
echo "sum of $value1 and $value2 is: $sum"
  • run
houbinbindeMacBook-Pro:shell houbinbin$ chmod +x num_oper.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./ num_oper.sh
sum of 10 and 20 is: 30

Math operator

Suppose: $a is 10, $b is 20

Command Desc Demo
+ 加法 expr $a + $b 结果为 30
- 减法 expr $a - $b 结果为 -10
* 乘法 expr $a \* $b 结果为 200
/ 除法 expr $b / $a 结果为 2
% 取余 expr $b % $a 结果为 0
= 赋值 a=$b 将把变量 b 的值赋给 a
== 用于比较两个数字,相同则返回 true [ $a == $b ] 返回 false
!= 用于比较两个数字,不相同则返回 true [ $a != $b ] 返回 true

Relation operator

Only support number or number string.

Suppose: $a is 10, $b is 20

Command Desc Demo
-eq equals [ $a -eq $b ] false
-ne not equals [ $a -ne $b ] true
-gt great than [ $a -gt $b ] false
-lt less than [ $a -lt $b ] true
-ge great equals [ $a -ge $b ] false
-le less equals [ $a -le $b ] true

Bool operator

Command Desc Demo
! not [ ! false ] true
-o or [ true -o false ] true
-a and [ true and false ] false
&& and [ true and false ] false
|| or [ true and false ] false

String operator

Suppose: $a is “10”, $b is “20”

Command Desc Demo
= 检测两个字符串是否相等,相等返回 true [ $a = $b ] 返回 false。
!= 检测两个字符串是否相等,不相等返回 true [ $a != $b ] 返回 true。
-z 检测字符串长度是否为0,为0返回 true [ -z $a ] 返回 false。
-n 检测字符串长度是否为0,不为0返回 true [ -n $a ] 返回 true。
str 检测字符串是否为空,不为空返回 true [ $a ] 返回 true。

File Test operator

Command Desc
-b file 检测文件是否是块设备文件,如果是,则返回 true
-c file 检测文件是否是字符设备文件,如果是,则返回 true
-d file 检测文件是否是目录,如果是,则返回 true
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true
-p file 检测文件是否是具名管道,如果是,则返回 true
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true
-r file 检测文件是否可读,如果是,则返回 true
-w file 检测文件是否可写,如果是,则返回 true
-x file 检测文件是否可执行,如果是,则返回 true
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true
-e file 检测文件(包括目录)是否存在,如果是,则返回 true
  • file_test_oper.sh
#!/bash/sh

# file test operator

file="/Users/houbinbin/code/shell/file_test_oper.sh"

if [ -r $file ]
then
   echo "文件可读"
else
   echo "文件不可读"
fi
if [ -w $file ]
then
   echo "文件可写"
else
   echo "文件不可写"
fi
if [ -x $file ]
then
   echo "文件可执行"
else
   echo "文件不可执行"
fi
if [ -f $file ]
then
   echo "文件为普通文件"
else
   echo "文件为特殊文件"
fi
if [ -d $file ]
then
   echo "文件是个目录"
else
   echo "文件不是个目录"
fi
if [ -s $file ]
then
   echo "文件不为空"
else
   echo "文件为空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi
  • run
houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh file_test_oper.sh
文件可读
文件可写
文件不可执行
文件为普通文件
文件不是个目录
文件不为空
文件存在

Shell Order

echo

echo [-e] string

printf

just like printf() of C

printf  format-string  [arguments...]

test

  • test_num.sh
#!/bin/bash

num1=100
num2=100
if test $[num1] -eq $[num2]
then
    echo '两个数相等!'
else
    echo '两个数不相等!'
fi

run

houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh test_num.sh
两个数相等!
  • test_str.sh
#!/bin/bash

num1="runoob"
num2="runoob"
if test num1=num2
then
    echo '两个字符串相等!'
else
    echo '两个字符串不相等!'
fi

run

houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh test_str.sh
两个字符串相等!
  • test_file.sh
#!/bin/bash

if test -e /bin/bash
then
    echo '文件已存在!'
else
    echo '文件不存在!'
fi

run

houbinbindeMacBook-Pro:shell houbinbin$ /bin/sh test_file.sh
文件已存在!

Flow Control

If Else

  • if
if condition
then
    command1
    command2
    ...
    commandN
fi
  • if else
if condition
then
    command1
    command2
    ...
    commandN
else
    command
fi
  • if else-if else
if condition1
then
    command1
elif condition2
then
    command2
else
    commandN
fi

demo

echo "please enter your age"
read age

if [[ $age -le 0 ||  $age -ge 100 ]]
then
echo "that's crazy!"

elif [ $age -le 20 ]
then
echo "little boy"

elif [[ $age -gt 20 &&  $age -le 40 ]]
then
echo "good time"

else
echo "be yourself"

fi

for

for loop in "hello" "boy" "see" "you" "sometimes" "somewhere"
do
echo "the word is $loop"
done

run

houbinbindeMacBook-Pro:shell houbinbin$ chmod +x for.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./for.sh
the word is hello
the word is boy
the word is see
the word is you
the word is sometimes
the word is somewhere

While

while condition
do
    command
done

demo

#!/bin/sh

# while demo

val=1
while( $val < 5 )
do
    echo "val: $val"
    let "val++"
done

run

houbinbindeMacBook-Pro:shell houbinbin$ ./while.sh
val: 1
val: 2
val: 3
val: 4

case

case val in
mode1)
    command1
    command2
    ...
    commandN
    ;;
mode2)
    command1
    command2
    ...
    commandN
    ;;
esac

demo

#!/bin/sh

# case demo

echo "please enter a num(1-4)"

echo you enter:

read num

case $num in
1)
    echo "Enter one"
    ;;
2)
    echo "Enter two"
    ;;
3)
    echo "Enter three"
    ;;
4)
    echo "Enter four"
    ;;

*)
    echo "Your enter is out of range"
    ;;
esac

run

houbinbindeMacBook-Pro:shell houbinbin$ vi case.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./case.sh
please enter a num(1-4)
you enter:
1
Enter one

beak

#!/bin/sh

# break demo

for num in 1 2 3 4 5
do
    if [ $num -eq 4 ]
    then
    break
    fi
    echo "num is: $num"
done

run

houbinbindeMacBook-Pro:shell houbinbin$ ./break.sh
num is: 1
num is: 2
num is: 3

continue

#!/bin/sh

# continue demo

for num in 1 2 3 4 5
do
    if [ $num -eq 4 ]
    then
    continue
    fi
    echo "num is: $num"
done

run

houbinbindeMacBook-Pro:shell houbinbin$ ./continue.sh
num is: 1
num is: 2
num is: 3
num is: 5

Func

[ function ] funname [()]

{

    action;

    [return int;]

}

demo

#!/bin/sh

# function demo

firstFunc() {
    echo "This is my first shell function."
}

echo "function start"
firstFunc
echo "function end"

run

houbinbindeMacBook-Pro:shell houbinbin$ vi function.sh
houbinbindeMacBook-Pro:shell houbinbin$ chmod +x function.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./function.sh
function start
This is my first shell function.
function end
  • function with return value
#!/bin/sh


# func with return val

funcWithReturnVal() {
    echo "enter first num: "
    read firstNum
    echo "enter second num: "
    read secondNum
    return $(($firstNum+$secondNum))
}

echo "function with return value start:"
funcWithReturnVal
returnVal=$?
echo "result: $returnVal"

run

houbinbindeMacBook-Pro:shell houbinbin$ ./funcWithReturnVal.sh
function with return value start:
enter first num:
1
enter second num:
2
result: 3
  • function with parameters
#!/bin/sh

# function with param

hasParam() {
    echo "all param is $*"

    if [ $# -gt 0 ]
    then
    echo "has param"
    return 1
    else
    echo "has no param"
    return 0
    fi
}

hasParam 1 2 3

run

houbinbindeMacBook-Pro:shell houbinbin$ vi funcWithParam.sh
houbinbindeMacBook-Pro:shell houbinbin$ chmod +x funcWithParam.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./funcWithParam.sh
all param is 1 2 3
has param

$n to get the param value, when n >= 10, use ${n}!

File Include

  • data.sh
#!/bin/sh

name="houbinbin"
  • include.sh

use . ./data.sh or source ./data.sh to include the file

#!/bin/sh

source ./data.sh

echo "the name is: $name"

run

houbinbindeMacBook-Pro:shell houbinbin$ chmod +x include.sh
houbinbindeMacBook-Pro:shell houbinbin$ ./include.sh
the name is: houbinbin

Redirect

Command Desc
command > file out->file
command < file in->file
command » file out append->file
n > file file descriptor n ->file
n » file file descriptor n append->file
n >& m out file m&n merge
n <& m in file m&n merge
« tag content between tag for input

File descriptor

0   //stdIn
1   //stdOut
2   //stdErr
  • Out Redirect
houbinbindeMacBook-Pro:shell houbinbin$ ls > ls_file
houbinbindeMacBook-Pro:shell houbinbin$ cat ls_file
break.sh
case.sh
continue.sh
data.sh
diff_demo.sh
file_test_oper.sh
for.sh
funcWithParam.sh
funcWithReturnVal.sh
function.sh
hello.sh
hello_name.sh
if_else.sh
include.sh
ls_file
num_oper.sh
readonly_var.sh
special_var.sh
test_file.sh
test_num.sh
unset_var.sh
use_var.sh
while.sh
  • In Redirect

We want to calc the line of file ls_file

houbinbindeMacBook-Pro:shell houbinbin$ wc -l ls_file
      23 ls_file