Shell 教程

563 阅读5分钟

Shell 教程

新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行

示例:

#!/bin/bash
echo "Hello World !"

#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序 echo 向窗口输出文本

运行:

  • 作为执行程序

    chmod +x ./test.sh  #使脚本具有执行权限
    chmod 755 test.sh #使脚本具有执行权限
    ./test.sh  #执行脚本
    sh test.sh  #执行脚本
    
  • 作为解释器参数

    /bin/sh test.sh
    /bin/php test.php
    

变量

定义变量

变量名不加 $
==变量名与等号不能有空格==

变量命名的规范:

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头
  • 中间不能有空格,可以使用下划线(_)
  • 不能使用标点符号
  • 不能使用bash里的关键字(可用help命令查看保留关键字)

使用变量

使用一个定义过的变量,只要在变量名前面加美元符号

your_name="qinjx"
echo $your_name
echo ${your_name}

readonly myUrl #只读

unset your_name #删除变量

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界 推荐给所有变量加上花括号

readonly 定义为只读变量,只读变量的值不能被改变 unset 变量被删除后不能再次使用。unset 命令不能删除只读变量

变量的类型

shell运行中的三种变量

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

字符串

# 单引号
str='this is a string'
# 双引号
str="Hello, I know you are \"$your_name\"! \n"
# 获取字符串长度
echo ${#str} #输出
# 截取字符串
echo ${str:1:4} # 输出 ello 从字符串第 2 个字符开始截取 4 个字符
# 查找字符串
echo `expr index "$str" io`  # 输出 4

单引号 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用

双引号 双引号里可以有变量 双引号里可以出现转义字符

反引号 反引号是命令替换;命令替换是指 shell可以先执行``中的命令,将输出结果暂时保存,在适当的时候输出

数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小

# 定义数组
数组名=(值1 值2 ... 值n)
arr=(1 2 3 4)
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
# 下标的范围没有限制

# 读取数组
${数组名[下标]}
${arr[0]}     # 1
echo ${arr[@]}
echo ${arr[*]}

# 获取数组长度
echo ${#arr[@]}
echo ${#arr[*]}

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

使用 @ 符号可以获取数组中的所有元素

注释

以 # 开头的行就是注释,会被解释器忽略。 多行注释

传递参数

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推…… $0 为执行的文件名(包含文件路径)

参数处理说明
$#传递到脚本的参数个数
$*以一个单字符串显示所有向脚本传递的参数。 如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@$*相同,但是使用时加引号,并在引号中返回每个参数。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$-显示Shell使用的当前选项,与set命令功能相同。
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

数组(见变量-数组)

运算符

原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。

expr 是一款表达式计算工具,使用它能完成表达式的求值操作。

#!/bin/bash

val=`expr 2 + 2`
echo "result is : $val"

执行结果为:

result is 4

两个数相加(注意使用的是反引号` 而不是单引号 ') 两点注意:

  • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2
  • 完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号

算数运算符

运算符说明举例
+加法`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。

注意

  • 条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。
  • 乘号(*)前边必须加反斜杠(\)才能实现乘法运算
  • 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "\"

关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

...

echo命令

输出字符串

#!/bin/sh
read name 
echo "$name It is a test"

echo -e "OK! \n" # -e 开启转义
echo -e "OK! \c" # -e 开启转义 \c 不换行

# 结果定向至文件
echo "It is a test" > myfile

# 原样输出字符串
echo '$name\"'

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

printf命令

流程控制

条件语句

sh 的流程控制不可为空,如果 else 分支没有语句执行,就不要写这个 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

循环语句


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

# while语句
while condition
do
    command
done

## 无限循环
while :
do
    command
done

while true
do
    command
done

for (( ; ; ))

# until循环
until condition
do
    command
done

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

当变量值在列表里,for 循环即执行一次所有命令,使用变量名获取列表中的当前取值。命令可为任何有效的 shell 命令和语句。in 列表可以包含替换、字符串和文件名。

in列表是可选的,如果不用它,for循环使用命令行的位置参数。

break命令允许跳出所有循环(终止执行后面的所有循环)。 continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

函数

#!/bin/bash

# 定义函数,一定要在使用前
add(){
echo '请输入第一个数'
read a

echo '请输入第二个数'
read b

echo "输入的树分别为:$a  $b"

return $(($a+$b))
}

# 调用函数
add

# 返回结果,获取结果使用 $?
echo "相加的结果为 $?"

  • 函数返回值在调用该函数后通过 $? 来获得。
  • 注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。

函数参数

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...

#!/bin/bash

funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

结果为

第一个参数为 1 ! 第二个参数为 2 ! 第十个参数为 10 ! 第十个参数为 34 ! 第十一个参数为 73 ! 参数总数有 11 个! 作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !

10不能获取第十个参数,获取第十个参数需要10 不能获取第十个参数,获取第十个参数需要{10}。当n>=10时,需要使用${n}来获取参数。

参数处理说明
$#传递到脚本或函数的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$! |后台运行的最后一个进程的ID号 $@ |与$*相同,但是使用时加引号,并在引号中返回每个参数。 $- |显示Shell使用的当前选项,与set命令功能相同。 $? |显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 ## 输入输出重定向 ``` shell ``` ### 输出重定向 ``` shell command > file ``` 执行command命令,然后将输出的内容存入file file如果原来有内容,将被覆盖,如果想要追加,使用 `>>`操作符 ### 输入重定向 ``` shell command < file ``` ### 重定向 - 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。 - 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。 - 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。 ``` shell # stderr 重定向到 file command 2> file # stdout 1 和 stderr 2 合并后重定向到 file command > file 2>&1 ``` ### /dev/null 文件 如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。 ## 文件包含 示例 test1.sh如下 ``` shell #!/bin/bash name="World" ``` test2.sh如下 ``` shell #!/bin/bash #使用 . 号来引用test1.sh 文件 . ./test1.sh # 或者使用以下包含文件代码 # source ./test1.sh echo "Hello:$name" ``` 注:被包含的文件 test1.sh 不需要可执行权限。 ## shell命令 dirname 取给定路径的目录部分 basename 取得文件名称部分 ``` shell $(dirname "$0") // 取脚本所在路径目录 ``` 实例: ``` shell # test.sh dir=`dirname $0` ame=`basename $0` echo $dir echo $name # prompt $ ./test.sh . test.sh ``` ``` shell var=222 echo ${var:=333} ``` `:=` 如果这个变量是空的或者未赋初值,则对其进行赋值. 否则, 就不赋值. shift shift 命令每执行一次,变量的个数($#)减一,而变量值提前一位 ## Linux Crontab 定时任务 linux内置的cron进程可实现定时任务 命令 `corntab` 是 corn table 的缩写 意为定时任务表 ### 有几个命令 常用 不常用的请 `man crontab` - `crontab -u user` - `crontab -l` 列出当前用户的任务 - `crontab -e` 编辑当前用户的任务 - `crontab -r` 删除任务表 ### 如何添加一个计划任务步骤 1. 创建你的脚本。 比如我的脚本名为 **mytest.sh** ``` shell # mytest.sh echo 111111 >> /test ``` 2. 编辑定时任务 `crontab -e` 进入vim编辑状态,键入命令 `* * * * * sh /home/mytest.sh` :wq 保存 定时任务创建完成 完成后会在 /var/spool/cron 目录下创建以你的用户名为名字的文件,内容也是你的命令 ### 查看定时任务 ``` shell crontab -l ``` ### 删除定时任务 - `crontab -r` 删除所有任务 - `crontab -e` 编辑删除指定任务 ### 几个目录(文件)了解一下 - **/var/spool/cron/** 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名 - **/etc/crontab** 这个文件负责调度各种管理和维护任务。 - **/etc/cron.d/** 这个目录用来存放任何要执行的crontab文件或脚本 - 脚本放在 **/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly** 目录中,让它每小时/天/星期、月执行一次。 **参考文献**: 1. [Shell 教程 | 菜鸟教程](https://www.runoob.com/linux/linux-shell.html)