shell 脚本教程

指定解释器

#!/bin/bash

基本语法

变量

变量类型

  • 局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量
  • 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量
  • shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行

变量操作

  • 创建普通变量:name=“test”,组要注意的是等号两边不能有空格。执行这一行后,被删除前全局都可以访问
  • 创建局部变量:local name=“test”,使用local修饰的变量在函数体外无法访问,只能在函数体中使用
  • 创建只读变量:name=“only_read” -> readonly name,这种变量不可以被修改
  • 使用变量:echo $name或者echo $
  • 删除变量:unset name,删除之后的变量无法被访问,需要注意无法删除只读变量

字符串变量

  1. var='str' 单引号中不能出现单独的单引号,转义也是不可以的
  2. var="my name is ${name}" 这种方式创建的字符串变量有效,也可以出现转义符
  3. str=('cascc \(s" 'ac'\)') 符号需要成对出现

拼接字符串

  1. 字面量拼接 str01="1""2"或者str01="1"'2',这样就将1和2两个字符拼接在了一起。需要注意的是两个串之间不可以有空格
  2. str03=${part01}${part02}str04=${part01}"end"str05="${part01} ${part02}"这三种方式都可以拼接字符串变量
  3. str02= `date`“end”,这里的date是一个shell命令,需要使用引用

获取字符串长度

  1. 使用wc -L命令:echo "abc" |wc -L
  2. 使用expr length可以获取string的长度
    expr length '1234567'
    
  3. 通过echo ${#name}的方式
    a='abc'
    echo ${#a}
    

取子字符串

  1. 代码 意义
    ${varible##*string} 从左向右截取最后一个string后的字符串
    ${varible#*string} 从左向右截取第一个string后的字符串
    ${varible%%string*} 从右向左截取最后一个string后的字符串
    ${varible%string*} 从右向左截取第一个string后的字符串
    MYVAR=foodforthought.jpg
    echo ${MYVAR##*fo}
    
    >rthought.jpg
    
  2. ${varible:n1:n2}
    截取变量varible从n1到n2之间的字符串,可以根据特定字符偏移和长度,来选择特定子字符串
    EXCLAIM=cowabunga
    echo ${EXCLAIM:0:3}
    
    >cow
    

数组

如果说变量是存储单个变量的内存空间,那么数组就是多个变量的集合,它存储多个元素在一片连续的内存空间中。在bash中,只支持一维数组,不支持多维数组

数组定义与引用

数组名=(元素1 元素2 元素3 ... 元素n)
数组名[下标]=值
数组名=([下标1]=值1 [下标2]=值2 ... [下标n]=值n)
${数组名[下标]}

遍历数组元素

使用 forwhile 循环便利数组元素

a=(1 2 3 4 5 6)
for((i=0; i<10; i++))
do
    echo "a[$i]=${a[$i]}"
done

除此以外我们还可以使用 ${a[*]}或者 ${a[@]} 来遍历数组元素

a=(1 2 3 4 5 6)
echo "${a[*]}"
echo "${a[@]}"

获取数组长度

我们可以使用 # 来获取数组长度,需要注意的是在shell脚本中越界访问数组时不会报错

a=(1 2 3 4 5 6)
echo "${a[*]}"
echo "a len: ${#a[*]}"

>1 2 3 4 5 6
>a len: 6

先使用其获取数组中的元素后使用#获取元素个数即可

合并数组

a=(1 2 3 4 5 6)
b=("hello" "zhaixue.cc")
c=("${a[*]}" "${b[*]}")
echo "${c[@]}"

>1 2 3 4 5 6 hello zhaixue.cc

删除数组元素

a=(1 2 3 4 5 6)
echo "${a[*]}"
echo "a len: ${#a[*]}"
unset "a[5]"
echo "${a[*]}"
echo "a len: ${#a[*]}"
unset a

>1 2 3 4 5 6
>a len: 6
>1 2 3 4 5
>a len: 5

变量传参

变量含义
$0代表执行的文件名
$1代表传入的第1个参数
$n代表传入的第n个参数
$#参数个数
$*以一个单字符串显示所有向脚本传递的参数。
$@与$*相同,但是使用时加引号,并在引号中返回每个参数
$$脚本运行的当前进程号
$!后台运行的最后一个进程的ID
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

运算符

算术运算符

条件表法式需要放在方括号之间,并且要有空格。使用expr进行计算时需要使用反引号
+ - * / % = [ $a == $b ] [ $a != $b ]

a=10
b=20
 
val=$(expr $a + $b)
echo "a + b : $val"

关系运算符

只支持数字,不支持字符串,除非字符串的值是数字

运算shell中的实现主要符号
检测两个数是否相等[ \$a -eq \$b ]-eq
检测两个数是否不相等[ \$a -ne \$b ]-ne
检测左边的数是否大于右边的[ \$a -gt \$b ]-gt
检测左边的数是否小于右边的[ \$a -lt \$b ]-lt
检测左边的数是否大于等于右边的[ \$a -ge \$b ]-ge
检测左边的数是否小于等于右边的[ \$a -le \$b ]-le
a=1
b=2

if [ $a != $b ]; then
    echo "$a != $b : a 不等于 b"
else
    echo "$a == $b: a 等于 b"
fi

>1 != 2 : a 不等于 b

布尔运算符

  1. !
    [ ! false ] ==注意 !false 中间的空格
  2. 或运算 -o
    [ $a -lt 20 -o $b -gt 100 ]
  3. 与运算 -a
    [ $a -lt 20 -a $b -gt 100 ]

逻辑运算符

  1. 逻辑 AND &&
    [[ $a -lt 100 && $b -gt 100 ]]
  2. 逻辑 OR ||
    [[ $a -lt 100 || $b -gt 100 ]]

字符串运算符

运算shell中的实现主要符号
检测两个字符串是否相等[ \$a = \$b ]=
检测两个字符串是否不相等[ \$a != \$b ]!=
检测字符串长度是否为0[ -z \$a ]-z
检测字符串长度是否不为 0[ -n “\$a” ]-n
检测字符串是否为空[ \$a ]\$

文件测试运算符

运算shell中的实现主要符号
检测文件是否是块设备文件[ -b \$file ]-b file
检测文件是否是字符设备文件[ -c \$file ]-c file
检测文件是否是目录[ -d \$file ]-d file
检测文件是否是普通文件(既不是目录,也不是设备文件)[ -f \$file ] 返回 true-f file
检测文件是否设置了 SGID 位[ -g \$file ]-g file
检测文件是否设置了粘着位(Sticky Bit)[ -k \$file ]-k file
检测文件是否是有名管道[ -p \$file ]-p file
检测文件是否设置了 SUID 位[ -u \$file ]-u file
检测文件是否可读[ -r \$file ]-r file
检测文件是否可写[ -w \$file ]-w file
检测文件是否可执行[ -x \$file ]-x file
检测文件是否为空(文件大小是否大于0)[ -s \$file ]-s file
检测文件(包括目录)是否存在[ -e \$file ]-e file
```bash file="/home/westos/Desktop/textcpp/test.sh" if [ -r $file ] then echo "文件可读" else echo "文件不可读" fi ```

运算指令

  1. (())
    可以直接使用双圆括弧计算其中的内容,如((var=a+b)),该指令经常在if/while等条件判断中需要计算时使用
  2. let
    在计算表达式的时候可以直接使用let,如let var=a+b
  3. expr
    ```var=`expr a+b````
  4. bc计算器
    bc计算器支持shell中的小数进行运算,并且可以交互式或者非交互式的使用。基本使用方式为 var=$(echo "(1.1+2.1)"|bc)
  5. $[]
    可以直接使用这种方式计算中括弧中的内容,如 echo $[1+2]

控制语句

if

# if-fi
if condition
then
    command1 
    command2
    ...
    commandN 
fi

# if-else-fi
if condition
then
    command1 
else
    command2
fi

# if else-if else
if condition1
then
    command1
elif condition2 
then
    command2
else
    command3
fi

for

for var in item1 item2 ... itemN
do
    command1
    command2
    ...
    commandN
done

例如:

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

while

while condition
do
    command
done

例如:

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

无限循环:

for (( ; ; ))

while :
do
    command
done

while true
do
    command
done

until循环

until condition
do
    command
done

跳出循环

  • break
  • continue

case-esac多选择语句

类似其他语言的 switch

格式如下

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
   *)
    command1
esac

select-in语句

select in是shell中独有的一种循环,非常适合终端的交互场景,它可以显示出带编号的菜单,用户出入不同编号就可以选择不同的菜单,并执行不同的功能

select var  in seq
do
    action
done
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
  break;
done
echo "You have selected $var"

函数

定义函数

[ function ] funname [()]
{
    action;
    [return int;]
}

注意
1. 以上的[ function ]也可以省略
2. 当函数没有return时,默认返回最后一个命令的运行结果作为返回值

函数参数

在shell中,调用函数时可以向其传递参数。在函数内部直接通过 $n 获取参数的值

funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第十个参数为 ${10} !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

需要注意\(10不能返回第十个参数,当n>10的时候,需要使用\)(n)来获取参数。

函数作用域

Shell脚本中执行函数时并不会开启子进程,默认在函数外部或函数内部定义和使用变量的效果相同。函数外部的变量在函数内部可以直接调用,反之函数内部的变量也可以在函数外部直接调用。但是这样会导致变量混淆、数据可能被错误地修改等等问题,那么如何解决这些问题呢?

系统为我们提供了一个local语句,该语句可以使在函数内部定义的变量仅在函数内部有效。定义时直接在变量前加 local 即可

重定向

一个命令通常从一个叫标准输入的地方读取输入,默认情况下,这恰好是你的终端。同样,一个命令通常将其输出写入到标准输出,默认情况下,这也是你的终端。

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:

标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
但有些时候我们可能需要将数据从其它文件读入或读出,这就需要重定向。

输入重定向

command1 < file

输出重定向

command1 > file

Here Document

Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。基本语法如下:

command << delimiter    documentdelimiter

注意:
结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。开始的delimiter前后的空格会被忽略掉。

/dev/null 文件

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null中,/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。语法如下

command > /dev/null
posted @ 2023-06-04 16:30  我的名字好长啊  阅读(28)  评论(0)    收藏  举报