shell编程入门

126 阅读9分钟

#博学谷IT学习技术支持#

1. 简介

shell脚本执行方式Shell 是一个用 C 语言编写的程序,通过 Shell 用户可以访问操作系统内核服务。它类似于 DOS 下的 command 和后来的 cmd.exe。Shell 既是一种命令语言,又是一种程序设计语言。

Shell script 是一种为 shell 编写的脚本程序。Shell 编程一般指 shell脚本编程,不是指开发 shell 自身。

Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。

Linux 的 Shell 种类众多,一个系统可以存在多个 shell,可以通过 cat /etc/shells 命令查看系统中安装的 shell。

Bash 由于易用和免费,在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。

2. 解释器

Java需要虚拟机解释器, 同理 shell脚本也需要解析器,查看Linux系统支持的解释器:

 [root@node1 shell]# cat / etc / shells/bin/sh/bin/bash/sbin/nologin/bin/dash/bin/tcsh/bin/csh

常见Shell解释器:

  • sh :全称是 Bourne shell,由 AT&T 公司的 Steve Bourne开发,为了纪念他,就用他的名字命名了。sh 是UNIX 上的标准 shell,很多 UNIX 版本都配有 sh。sh 是第一个流行的 Shell。
  • Bash: 从名称可以看出是Bsh的升级版本,是著名的开源软件项目,目前大多数的Linux版本都使用Bash 作为默认的Shell程序,当运行Shell程序时,实际运行的是Bash程序
  • Csh: 是因使用C语言的语法风格而得名,在用户的命令行交互界面上进行了很多改进,并增加了历史,别名,文件名替换,作业掏等功能,相比Bsh,Csh在更加适用为 用户提供命令交互操作 在现代的 Linux上,sh 已经被 bash 代替,/bin/sh往往是指向/bin/bash的符号链接。 如果你希望查看当前 Linux 的默认 Shell,那么可以输出 SHELL 环境变量:
[ root @ node1 shell ] # echo $SHELL **/** bin / bash

输出结果表明默认的 Shell 是 bash

4. shell脚本执行方式

shell脚本有三种执行方式: 方式一:sh执行脚本 sh执行,进入脚本的工作目录,然后使用对应的sh或bash来执行脚本, 种执行方式,脚本文件不需要具有可执行权限

 [ root @ node1 ~] # cd / export / data / shell / 
 [ root @ node1 shell ] #sh hello.sh 
hello world

方式二:工作目录执行 执行脚本时,先进入到脚本所在的目录,然后使用 ./脚本方式执行,这种执行方式,必须保证脚本文件具有可执行权限

[root@node1 ~]#cd / export / data / shell /
[root@node1 shell]# chmod +x hello.sh 
[root@node1 shell]# ./ hello.sh 
hello world

方式三:绝对路径执行 绝对路径中执行,指的是直接从根目录/到脚本目录的绝对路径,这种执行方式,必须保证脚本文件具有可执行权限

[root@node1 ~]# /export/shell/hello.sh 
hello world

5. shell的数据类型

字符串: 字符串是shell编程中最常用最有用的数据类型,字符串可以用单引号,也可以用双引号,也可以不用引号。建议使用双引号,因为双引号里可以有变量和特殊字符,可以按照变量和特殊字符去使用。 声明字符串类型的变量:

整数型: 在Shell中所有的变量默认都是字符串型。默认情况下,所有的数值都是不能进行运算的,如果想要进行数学运算,可以使用“((运算式))”或“[运算式]”方式运算

6. 变量

6.1. 简介

shell变量是一种很“弱”的变量,默认情况下,一个变量保存一个串,shell不关心这个串是什么含义。所以若要进行数学运算,必须使用一些命令例如let、declare、expr、双括号等。

在shell中有3种变量:用户变量、环境变量、特殊变量,其中用户变量在编程过程中使用量最多,环境变量主要是在程序运行时需要设置,特殊变量在对参数判断和命令返回值判断时会使用。

  • 变量的定义语法: 变量名=变量值
  • 变量的定义需遵循的规则
  1. 变量名可以由字母、数字和下画线组成,但是不能以数字开头。
  2. 在 Bash中,变量的默认类型都是字符串型,如果要进行数值运算,则必须使用特殊命令。
  3. 变量用等号"="连接值,"="左右两侧不能有空格。
  4. 变量值中如果有空格,则需要使用单引号或双引号包含,如 test="hello world!"。双引号括起 来的内容"$"和反引号者都拥有特殊含义,而单引号括起来的内容都是普通字符。
  5. 在变量值中,可以使用转义符""。
  6. 不能使用bash里的关键字(可用help命令查看保留关键字)。

6.2. 用户变量

定义变量

在对变量赋于字符串值时,建议使用引号将其包裹。如果字符串中存在空格,请一定要使用单引号或双引号将整个内容包裹。注意:单引号里的内容原封不动的输出,双引号里有变量的调用则会调用变量

[root@node1 shell]# username="itcast"
访问变量

要对变量进行调用时,在变量名前加美元符号$

[root@node1 shell]# echo $username

如果需要增加变量的值,那么可以进行变量值的叠加。不够变量需要用双引号包含"变量名""变量名"或{变量名}

变量的其他赋值方式
  • 1) 可以使用read关键字从键盘获取内容赋值给变量
  • 2) 可以通过(linux命令)或者(linux命令)或者linux命令来执行linux命令,并将命令的执行结果赋值给变量
#!/bin/bash 
echo "who are you?" 
read name  #从键盘获取变量的值 
pwd_string=$(pwd) #将当前的绝对路径赋值给pwd_string变量 
date_string=`date` #将当前时间赋值给date_string变量,注意这里使用的是反引号
echo "hello, $name" 
echo $pwd_string 
echo $date_string 
"""
who are you?
itcast
hello, itcast
/export/data/shell
2020年 05月 10日 星期日 16:50:21 CST
"""
只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。

readonly myUrl
删除变量

使用 unset 命令可以删除变量。语法: unset variable_name 变量被删除后不能再次使用。unset 命令不能删除只读变量

6.3. 环境变量

当shell程序启动时,都自动设置一组变量,这组变量就是环境变量。shell中的所有命令都可以使用这些变量,环境变量可以在/etc/profile中设置,环境变量的名字习惯上使用大写字母。 系统环境变量:/etc/profile 用户环境变量: 用户家目录/bash_profile

常见的环境变量

可以使用env命令查看所有的系统环境变量

[root@node1 shell]# env
XDG_SESSION_ID=2
HOSTNAME=node1
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.88.5 8047 22
CONDA_SHLVL=0
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root

常见的环境变量:

  • PATH 决定了shell将到哪些目录中寻找命令或程序
  • HOME 当前用户主目录
  • HISTSIZE 历史记录数
  • LOGNAME 当前用户的登录名
  • HOSTNAME 指主机的名称
  • SHELL 当前用户Shell类型
  • LANGUGE 语言相关的环境变量,多语言可以修改此环境变量
  • MAIL 当前用户的邮件存放目录
  • PS1 基本提示符,对于root用户是#,对于普通用户是$
自定义环境变量
    1. vi /etc/profile ,在文件末尾加上要定义的环境变量,语法如下:
    • export 变量名=变量值
    • export SERVICE_HOST**=localhoust**
    1. wq 退出
    1. source /etc/profile
    1. 输入 env 查看环境变量,是否有自己定义的环境变量。
    1. 使用环境变量
    • 环境变量的使用方式和普通变量是一样的: $环境变量名

6.4. 特殊变量

在执行 Shell 脚本时,向脚本传递参数,这时候可以使用特变变量来获取参数,Shell常用的特殊变量如下:

变量解释
$#命令行参数的个数
$n1表示第一个参数,1表示第一个参数,2表示第二个参数,以此类推
$0当前程序的名称
$?前一个命令或许或函数的返回码
$*以“参数1参数2。。。”形式保存所有参数
$@以“参数1”“参数2”。。。形式保存所有参数
$$本程序的(进程ID号)PID
$!上一个命令的PID
* 与 @ 区别:
  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " "等价于"123"(传递了一个参数),而"* " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)

7. 字符串

字符串可以用单引号,也可以用双引号,也可以不用引号。

7.1. 单引号

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

7.2. 双引号

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

7.3. 拼接字符串

#!/bin/bash
yourname="吴恩达"
wenhou_1="你好,$yourname ."
wenhou_2="你好," $yourname" ."
wenhou_3="你好,"$yourname" ."
echo $wenhou_1 $wenhou_2 $wenhou_3

7.4. 获取字符串长度

echo ${#string}   # 输出结果: 4

7.5. 提取子字符串

string="敢于亮剑决不后退"
echo ${string:2:3}    # 输出结果为: 亮剑决

8. 算术运算符

Shell 和其他编程一样,支持包括:算术、关系、布尔、字符串等运算符。原生 bash 不支持简单的数学运算,但是可以通过其他命令来实现 注意:

  • 表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2。
  • 完整的表达式要被` `包含,注意不是单引号,在 Esc 键下边。 | 运算符 | 说明 | 举例 | | --- | ------------------------- | ------------------------ | | + | 加法 | 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 ]。

例子

#!/bin/bash 
a=4
b=20
#加法运算 
echo `expr $a + $b`
#减法运算 
echo `expr $a - $b`
#乘法运算,注意*号前面需要反斜杠 
echo `expr $a * $b`
#除法运算 
echo `expr $a / $b`
#此外,还可以通过$(())、$[]进行算术运算。 
echo "a = $a" 
c=$(( a+b ))
d=$[a+ b ]
echo "c = $c" 
echo "d = $d"

9. 流程控制

9.1. 语句判断

数字
运算符说明
-eq检测两个数是否相等,相等返回 true。
-ne检测两个数是否不相等,不相等返回 true。
-gt检测左边的数是否大于右边的,如果是,则返回 true。
-lt检测左边的数是否小于右边的,如果是,则返回 true。
-ge检测左边的数是否大于等于右边的,如果是,则返回 true。
-le检测左边的数是否小于等于右边的,如果是,则返回 true。
字符串
判断符说明
-n STRING字符串长度不为零
-z STRING字符串长度为0
=判断两个字符串是否一样
!=判断两个字符串是否不一样
文件
判断符说明
-f存在且是普通文件
-d存在且是目录
-h存在且是符号链接
-e文件存在
–r文件存在并且可读
–w文件存在并且可写
–x文件存在并且可执行

9.2. if语句

if 语句语法格式:
if [ condition ]
then
    commandN 
fi
# 判断当前系统是否有多个ssh进程,如果有则打印tru
#!/bin/bash
if [ $(ps -ef " grep -c "ssh") -gt 1 ]
then 
 echo "true" 
fi
#  判断/media/cdrom文件是否存在,若不存在就去创建这个目录
#!/bin/bash 
DIR="/media/cdrom" 
if [ ! -e $DIR ] 
then 
mkdir -p $DIR 
fi
if then else
if else-if else

9.3. for循环

格式1-字符型循环
For xx in x1,x2,x3
do
    Main
done

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

格式2-数字性循环
for ((初始值;循环控制条件;变量变化))
do
    程序
done

需要注意以下几点:

  • 初始值:在循环开始时,需要给某个变量赋予初始值
  • 循环控制条件:用于指定变量循环的次数
  • 变量变化:每次循环之后,变量该如何变化,如 i=i+1,代表每次循环之后,变量的值都加 1。

9.4. while循环

while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件。其格式为

while 条件
do
    程序
done

使用中使用了 Bash let 命令,它用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量,具体可查阅Bash let 命令

9.5. 无限循环

while: 
While true:
For (( ; ; ))

9.6. case语句

Shell case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:


casein
    1)
        command1
        command2
        ...
        commandN
        ;;
    2)
        command1
        command2
        ...
        commandN
        ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
esac

case工作方式如上所示。取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ; 取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。 下面的脚本提示输入1到4,与每一种模式进行匹配:

9.7. 跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue

break

break命令允许跳出所有循环(终止执行后面的所有循环)。

continue

仅仅跳出当前循环。

10. 函数

10.1. 语法


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

可以带function fun() 定义,也可以直接fun() 定义,不带任何参数

10.2. 函数参数

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

funname 1 2 3 4

11 数组

数组中可以存放多个值。Bash Shell 只支持一维数组(不支持多维数组),初始化时不需要定义数组大小。 与大部分编程语言类似,数组元素的下标由0开始。 Shell 数组用括号来表示,元素用"空格"符号分割开,语法格式如下: array_name=(value1 ... valuen)

11.2. 读取数组

  ${array_name[index]}

11. 3 获取数组中的所有元素

使用@ 或 * 可以获取数组中的所有元素,例如:

echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"

11.4 获取数组的长度

echo "数组元素个数为: ${#my_array[*]}"
echo "数组元素个数为: ${#my_array[@]}"

11.5. 遍历数组

my_arr=( AA BB CC )

for var in ${my_arr[*]}
do
  echo $var
done
my_arr=( AA BB CC )
my_arr_num=${#my_arr[*]}
for(( i=0 ; i < my_arr_num ; i++ ));
do
  echo "-----------------------------"
  echo ${my_arr[$i]}
done

12 select

select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的值中进行选择:

select var in ... ;
do
 commond
done
.... now $var can be used ...

注意: select 是个无限循环,因此要记住用 break 命令退出循环,或用exit 命令终止脚本

#!/bin/bash
echo "What is your favourite OS?"
PS3="Please enter your choice:"
select var in "Linux" "Gnu Hurd" "Free BSD" "Other"
do
  break;
done
echo "You have selected $var"

这里PS3作为select语句的shell界面提示符,注意:PS3一定要定义在select语句的前面

#!/bin/bash
echo "你想学习什么语言?"
PS3="请输入你的选择:"    # 设置提示字符串
select var in java c++ shell python
do
  case $var in
     "java" )
       echo "恭喜你选择成功.java最牛"
     ;;
     "c++" )
       echo "驱动开发  网络优化  go 语言"
     ;;
     "shell" )
       echo "运维必会"
     ;;
     python)
       echo "人工智能"
     esac
     break    # 如果这里没有break 将会进行无限循环
done
echo "你选择的是:$var"

13. 加载其它文件的变量

13.1. 加载其它文件的变量

和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件。 Shell 文件包含的语法格式如下

. filename   # 注意点号(.)和文件名中间有一空格source filename 

#!/bin/bash
source ./ test1.sh  # 加载test1.sh 的文件内容
for var in ${my_arr[*]}
do
  echo $var
done