Linux–shell学习笔记(下)

判断语句

if…then 形式

类似于**C/C++中的if-else**语句


单层 if

命令格式:

if condition

then

  语句1

  语句2

  ...

fi

示例:

a=3

b=4

if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]

then

  echo ${a}在范围内

fi
# 输出结果:

# 3在范围内


单层 if-else

命令格式:

if condition

then

  语句1

  语句2

  ...

else

  语句1

  语句2

  ...

fi

示例:

a=3

b=4

if ! [ "$a" -lt "$b" ]

then

  echo ${a}不小于${b}

else

  echo ${a}小于${b}

fi

# 输出结果:

# 3小于4

多层 if-elif-elif-else

命令格式:

if condition

then

  语句1

  语句2

  ...

elif condition

then

  语句1

  语句2

  ...

elif condition

then

  语句1

  语句2

else

  语句1

  语句2

  ...

fi

示例:

a=4

if [ $a -eq 1 ]

then

  echo ${a}等于1

elif [ $a -eq 2 ]

then

  echo ${a}等于2

elif [ $a -eq 3 ]

then

  echo ${a}等于3

else

  echo 其他

fi

# 输出结果:

# 其他

case…esac 形式

类似于**C/C++中的switch**语句

命令格式:

case $变量名称 in

  值1)

    语句1

    语句2

    ...

    ;;  # 类似于C/C++中的break

  值2)

    语句1

    语句2

    ...

    ;;

  *)  # 类似于C/C++中的default

    语句1

    语句2

    ...

    ;;

esac

示例:

a=4

case $a in

  1)

    echo ${a}等于1

    ;;  

  2)

    echo ${a}等于2

    ;;  

  3)

    echo ${a}等于3

    ;;  

  *)

    echo 其他

    ;;  

esac

# 输出结果:

# 其他

循环语句

for…in…do…done

命令格式:

for var in val1 val2 val3

do

  语句1

  语句2

  ...

done

示例1,输出a 2 cc,每个元素一行:

for i in a 2 cc

do

  echo $i

done

示例2,输出当前路径下的所有文件名,每个文件名一行:

for file in `ls`

do

  echo $file

done

示例3,输出1-10:

for i in $(seq 1 10)

do

  echo $i

done

示例4,使用**{1..10}或者****{a..z}****:**

for i in {a..z}

do

  echo $i

done

for((…;…;…)) do…done

命令格式:

for ((expression; condition; expression))

do

  语句1

  语句2

done

示例,输出1-10,每个数占一行:

for ((i=1; i<=10; i++))

do

  echo $i

done

while…do…done

命令格式:

while condition

do

  语句1

  语句2

  ...

done

示例,文件结束符为**Ctrl + d,输入文件结束符后read指令返回false。**​

while read name

do

  echo $name

done

until…do…done

当条件为真时结束。

命令格式:

until condition

do

  语句1

  语句2

  ...

done

示例,当用户输入**yes**或者YES时结束,否则一直等待读入。

until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]

do

  read -p "Please input yes/YES to stop this program: " word

done

break 命令

跳出当前一层循环,注意与**C/C++不同的是:break不能跳出case**语句。

示例:

while read name

do

  for ((i=1; i<=10; i++))

  do

    case $i in

      8)

        break

        ;;

      *)

        echo $i

        ;;

    esac

  done

done

该示例每读入非**EOF**的字符串,会输出一遍1-7。

该程序可以输入**Ctrl + d文件结束符来结束,也可以直接用Ctrl + c**杀掉该进程。


continue 命令

跳出当前循环。

示例:

for ((i=1; i<=10; i++))

do

  if [ `expr $i % 2` -eq 0 ]

  then

    continue

  fi

  echo $i

done

该程序输出1-10中的所有奇数。


死循环的处理方式

输入**Ctrl + c**即可。

可以直接关闭进程:

ㅤㅤ●ㅤ使用top命令找到进程的PID

ㅤㅤ●ㅤ**输入kill -9 PID**即可关掉此进程


函数

**bash中的函数类似于C/C++中的函数,但return的返回值与C/C++不同,返回的是exit code,取值为0-2550**表示正常结束。

如果想获取函数的输出结果,可以通过**echo输出到stdout中,然后通过$(function_name)来获取stdout**中的结果。

函数的**return值可以通过$?**来获取。

命令格式:

[function] func_name() {  # function关键字可以省略

  语句1

  语句2

  ...

}

不获取return值和stdout

示例:

func()

{

  name=xhl

  echo "Hello $name"

}

func

# 输出结果:

# xhl

获取return值和stdout

不写**return时,默认return 0。**​

示例:

func()

{

  name=xhl

  echo "Hello $name"

  return 123

}

output=$(func)

ret=$?

echo "output = $output"

echo "return = $ret"

# 输出结果:

# output = Hello xhl

# return = 123

函数的输入参数

在函数内, **​$1表示第一个输入参数,$2**表示第二个输入参数,依此类推。

注意:函数内的**$0**仍然是文件名,而不是函数名。

示例:

func()  # 递归计算 $1 + ($1 - 1) + ($1 - 2) + ... + 0

{

  word=""

  while [ "${word}" != 'y' ] && [ "${word}" != 'n' ]

  do

    read -p "要进入func($1)函数吗?请输入y/n:" word

  done

  if [ "$word" == 'n' ]

  then

    echo 0

    return 0

  fi  if [ $1 -le 0 ] 

  then

    echo 0

    return 0

  fi  sum=$(func $(expr $1 - 1))

  echo $(expr $sum + $1)

}

echo $(func 10)

# 输出结果:

# 55

函数内的局部变量

可以在函数内定义局部变量,作用范围仅在当前函数内。

可以在递归函数中定义局部变量。

命令格式:

local 变量名=变量值

例如:

#! /bin/bash

func() {

  local name=xhl

  echo $name

}

func

echo $name

# 输出结果:

# xhl
# 第一行为函数内的name变量,第二行为函数外调用name变量,会发现此时该变量不存在。

exit 命令

**exit命令用来退出当前shell进程,并返回一个退出状态;使用$?**可以接收这个退出状态。

exit命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是0

**exit退出状态只能是一个介于0~255之间的整数,其中只有0**表示成功,其它值都表示失败

示例:

创建脚本**test.sh,内容如下:**​

#! /bin/bash

if [ $# -ne 1 ]  # 如果传入参数个数等于1,则正常退出;否则非正常退出。

then

  echo "arguments not valid"

  exit 1

else

  echo "arguments valid"

  exit 0

fi

bash test.sh

arguments valid

echo $?  # 传入一个参数,则正常退出,exit code为0

0

bash test.sh

arguments not valid

echo $?  # 传入参数个数不是1,则非正常退出,exit code为1

1

文件重定向

每个进程默认打开3个文件描述符:

ㅤㅤ●ㅤ**stdin标准输入,从命令行读取数据,文件描述符为0**

ㅤㅤ●ㅤ**stdout标准输出,向命令行输出数据,文件描述符为1**

ㅤㅤ●ㅤ**stderr标准错误输出,向命令行输出数据,文件描述符为2**

可以用文件重定向将这三个文件重定向到其他文件中。


重定向命令列表


输入和输出重定向

echo -e "Hello \c" > output.txt  # 将stdout重定向到output.txt中

echo "World" >> output.txt  # 将字符串追加到output.txt中

read str < output.txt  # 从output.txt中读取字符串

echo $str  # 输出结果:Hello World

同时重定向stdinstdout

创建**bash**脚本:

#! /bin/bash

read a

read b

echo $(expr "$a" + "$b")

# 创建input.txt,里面的内容为:

3

4

# 执行命令:

bash test.sh < input.txt > output.txt  # 从input.txt中读取内容,将输出写入output.txt中

cat output.txt  # 查看output.txt中的内容

7


引入外部脚本

类似于**C/C++中的include操作,bash**也可以引入其他文件中的代码。

语法格式:

. filename  # 注意点和文件名之间有一个空格source filename

示例:

创建**test1.sh,内容为:**​

#! /bin/bash

name=xhl  # 定义变量name

然后创建**test2.sh,内容为:**​

#! /bin/bash

source test1.sh # 或 . [test1.sh](http://test1.sh)

echo My name is: $name  # 可以使用test1.sh中的变量

执行命令:

bash test2.sh

My name is: xhl
06-23 05:39