一、概念
不同架构CPU所使用的指令集不同,编译器也不同。
(一)编译型语言和解释型语言
1. 编译型语言
在运行前需要专门有一个编译的过程,将方便人类识别的高级语言翻译成计算机识别的机器指令。
优点:执行前已经翻译过了,执行过程中无需重新翻译,所以执行效率相对较高
缺点:可移植性(跨平台)相对较差。
例:C语言、C++
2. 解释型语言(脚本语言)
运行前无需单独翻译,而是在运行过程由解释器逐行翻译给计算机。
优点:可移植性(跨平台性)相对较好,不依赖于编译器
缺点:每次执行都需要逐行重新翻译,执行效率相对较低
例:shell、python
(二)SHELL
1. shell
shell是命令行解释器。
/bin/bash
/bin/dash
- 注:dash 是 bash 的轻量级
2. shell脚本
以’.sh’结尾的文件(方便人识别出这是shell脚本文件,对计算机并不是硬性要求),里面是命令的集合以及一些复杂的逻辑。
目的:批量的执行命令
(1)执行
shell是解释型语言,无需编译,直接运行即可
方式1:./脚本名
方式2:bash 脚本名
方式3:source 脚本名
./
执行需要加执行权限,而bash
和source
不需要执行权限./
方式 和bash
方式是在后台新开了一个终端执行脚本,并把执行的结果返回当前终端;而source
就是直接在当前终端执行,如果脚本中更改了文件目录,使用source运行该脚本也会更改路径
二、shell语法
(一) shell变量
1. 变量
在shell中使用变量时无需提前定义,直接使用即可
shell每条指令结束无需加分号,多条指令放在一行可以用分号分隔
shell中的变量默认都是字符串,没有整型、浮点数之分
shell变量使用也要符合变量的命名规范:
(1)数字字母下划线
(2)不能数字开头
(3)不能和shell的关键字冲突(如cd、ls)
(4)最好能望文知意
(5)变量名习惯上大写
(1)shell中的变量默认都是字符串
A1=100+200
A2=hello
echo $A1
echo $S1
输出结果:
(2) 赋值运算符两侧不能有空格
等号右侧如果有空格,会将空格赋值给变量,然后将空格后面的值当作命令执行,然后报错
A1= hello #hello前有空格
echo $A1
等号左侧如果有空格,会将变量名当作命令执行,然后报错
A1 =hello #A1后有空格
echo $A1
2. 引用变量
$<变量名> 或 ${<变量名>}
例:$a
或 ${a}
不要使用 $(变量名)
,这是命令置换符
- 注:shell注释使用’#’
#!/bin/bash
V1=hello
V2=1:${V1}world
echo $V2 #1:helloworld
V3="hello world" #如果字符串不加引号,遇到空格就会停止,然后将空格后的world当作命令执行
echo 2:$V3 #2:hello world
echo "3:双引号可以引用变量:$V1 world" #hello world
echo '4:单引号不能引用变量:$V1 world' #$V1 world
echo "5:花括号使用:${V1}world" #helloworld
echo "6:不使用花括号会识别成为新变量,为空值:$V1world"
输出结果:
3.清空变量的值
unset <变量名>
用于清空本地环境变量
- 注意,后接变量名,不要加’$’
- 在shell中既可以使用自定义变量,也可以使用环境变量
4.位置变量
类似于C语言中main函数的参数
\$0
三种不同的执行方式值不同
./脚本名
$0就是 ./脚本名
bash
$0就是脚本名
source
$0就是bash
$1~9
命令行传递第一个到第九个
${10}
超过九个参数时使用花括号,使其成为一个整体
$@
执行脚本时命令行传的所有参数(不包括脚本名)
$*
执行脚本时命令行传的所有参数(不包括脚本名)
$#
执行脚本时命令行传的所有参数的个数(不包括脚本名)
$?
用来表示上一条命令是否执行成功 0成功;1没成功
$$
执行脚本的进程号
echo '$0='$0
echo '$2='$2
5. 作用域
shell如果不加任何修饰,作用域默认是全局
如果想定义局部变量,加关键字"local"
6. shell的只读变量
关键字"readonly"
对只读变量修改会报错
需要初始化,因为后面不支持再修改
readonly V1=hello
echo '$V1='$V1
V1=world
echo '$V1='$V1
输出结果:
7. 命令置换符
将命令执行的结果赋值给变量
$() 或两个反引号 ` `
LIST=$(ls)
echo LIST=$LIST
LIST2=`ls`
echo LIST2=$LIST2
输出结果:
(二) 注释
1. 单行注释
#使用’#'单行注释
2. 多行注释
shell中并未真正定义多行注释语法,下面的用法利用了输入重定向,所以如果注释的内容有 读取终端输入的指令 可能就会有问题
:<<EOF
多行注释
EOF
或者
:<<!
多行注释
!
(三) 字符串相关操作
1. 计算字符串长度
${#<变量名>}
readonly V1=hello
echo ${#V1}
不会将’\0’计算进去
输出结果:
2. 字符串拷贝
shell中变量本身就是字符串,所以字符串拷贝本身就是变量的赋值
V1=helloworld
V2=$V1
echo '$V2='$V2
输出结果:
3. 字符串拼接
STRING1= ${STRING2}hello
V1=hello
V2=${V1}world
echo '$V2='$V2
输出结果:
4. 字符串截取
(1)${STRING:<num>}
从左往右下标为0开始数,第num个字符开始,一直到结尾
S1=aabbccddeeffgghh
echo ${S1:4} #ddeeffgghh
输出结果:
(2)${STRING:<num1>:<num2>}
下标从0开始数,第num1个字符开始,截取num2个字符
S1=aabbccddeeffgghh
echo ${S1:4} #ddeeffgghh
输出结果:
(3)${STRING:0-<num>}
倒数下标从1开始数,从倒数第num个开始截取,一直到结尾
S1=aabbccddeeffgghh
echo ${S1:0-4} #gghh
输出结果:
(4)${STRING:0-<num1>:<num2>}
从倒数第num1个开始截取,截取num2个字符
S1=aabbccddeeffgghh
echo ${S1:0-4:2} #gg
输出结果:
(5)其他截取字符串的方法
从左向右 截取第一次出现 rr 后面的内容
STRING="qqwweerrttqqwweerrttqqww"
echo ${STRING#*rr}
从左向右 截取最后一次出现 rr 后面的内容;
STRING2=${STRING##*rr}
echo $STRING2
从右向左 截取第一次出现 rr 前面的内容
STRING3=${STRING%rr*}
echo $STRING3
从右向左 截取最后一次出现 rr 前面的内容
STRING4=${STRING%%rr*}
echo $STRING4
(四) shell中的数组
1. 数组
ARR=(1 2 3 4 5)
echo ${ARR[1]}
*注:
- shell只有一维数组,shell中的数组用()来表示
- shell的数组没有类型,默认都是字符串
- shell中的数组也无需提前定义
- 成员之间用空格分隔
- 下标也是从0开始
2. 赋值
数组名[下标]=新的值
ARR=(aa bb cc dd)
ARR[1]=ee
echo ${ARR[1]}
输出:
3. 引用
${ARR[1]}
4. 引用数组中所有的成员
${ARR[@]}
${ARR[*]}
赋值:
RET=${ARR[@]} #变量
RET=(${ARR[@]}) #数组
ARR=(aa bb cc dd)
RET=${ARR[@]}
RET2=(${ARR[*]})
echo RET #RET是一个字符串
echo RET2 #RET2是一个数组
5. 成员个数
${#ARR[@]}
${#ARR[*]}
ARR=(aa bb cc dd)
RET=${ARR[@]}
RET2=(${ARR[*]})
echo ${#RET} #RET是一个字符串
echo ${#RET2[@]} #RET2是一个数组
6. 追加成员
ARR=(11 22 ${ARR[@]} xx yy)
ARR=(aa bb cc dd)
ARR=(11 22 ${ARR[*]} 33 44)
RET=${ARR[@]}
echo $RET
(五)shell中的输入输出
1. 输出 echo
(1)echo自带换行符
A=hello
B=world
echo $A
echo $B
(2)-n 取消换行符
A=hello
B=world
echo -n $A
echo $B
(3)-e 识别字符串中的换行符
S=hello\nworld
echo "0:hello\nworld"
#只能识别字符串中的换行符
echo -e "1:hello\nworld"
echo -e '2:hello\nworld'
#下面两种方式不能成功使用
echo -e 3:hello\nworld
echo -e 4:$S
输出:
2. 输入 read
(1)允许一次输入多个变量的值,以空格分隔
read A
read B C
#允许一次输入多个变量的值,以空格分隔,但是这种写法,一旦字符串中有空格,就无法识别了,所以不建议使用
(2)添加提示信息 -p
read -p "提示信息>>" A
(3)等待输入时间 -t(秒为单位)
read -t 5 #表示等待用户输入,最多等五秒,五秒后会继续向下执行,不敲回车无法读取
(4)最多获取字符 -n
read -n 5 #表示最多获取5个字符,只要输入够五个,不敲回车也读取
(5)获取数组 -a
read -a A#表示输入的是一个数组
read -p"这是一个数组>>" -a A
echo 数组大小为:${#A[@]}
(6)取消回显 -s
read -s #取消输入的回显
选项可以一次使用多个,搭配使用,但是选项和参数成对使用
eg :终端读取用户输入的软件名,输入后下载该软件,并执行该软件
要求有提示信息,最多20字符,最多等待10秒
#!/bin/bash
#输入
read -p "请输入要下载的软件名称>>" -n 20 -t 10 NAME
#下载
sudo apt-get install $NAME
#执行
$NAME
(六)shell中的运算符
shell用来批量执行命令,并不是专门用来做复杂的算术运算的。
如果需要处理复杂的算术运算,可以在shell中调用C程序
shell一般用于处理一些简单的运算,如计数变量的自增
shell如果不使用运算符直接运算,所有变量都会当作字符处理
shell不支持浮点运算
第一种:(())
第二种:$[]
第三种:let
第四种:expr
以上四种运算方式 效率是递减的,expr可以做字符串处理
1. ((表达式1,表达式2,…,表达式n))
多个表达式之间用逗号分隔
当有多个表达式时,每个表达式都会参与运算,最后一个表达式的结果是整个表达式的结果
- 注:
- 1. (())内部引用变量值$可加可不加
- 2. 内部运算符前后的空格可加可不加
- 3. 如果想使用结果需要加$ 例:‘$(())’
- 4. 可以做复杂的算术运算,如变量自增自减以及for循环
- 5.如果做自增自减运算,变量前就不能加$
示例:((V1++))
read -p "please input V1: " V1
read -p "please input V2: " V2
echo "$V1 * $V2 = $((V1*V2))"
echo "++V1 = $((++V1))"
2. $[表达式1,表达式2,…,表达式n]
当有多个表达式时,每个表达式都会参与运算,最后一个表达式的结果是整个表达式的结果
V1=10;V2=20;V3=30;
V=$[++V1,++V2,++V3]
echo V=$V
echo V1=$V1" "V2=$V2
输出结果:
- 注:
- 1. 内部引用变量值$可加可不加
- 2. 内部运算符前后的空格可加可不加
- 3. 结果必须有变量来接或者echo到终端,否则报错
- 4. 不能做复杂的运算,可以执行自加自减操作,不能执行for运算
3. expr
V2=20;V3=30;
expr $V2+$V3
expr $V2 + $V3
- 注:
- 1. expr内部引用变量值时$必须加,不加报错
- 2. 内部运算符前后的空格必须加 ,不加空格当字符串处理
- 3. 自动将结果打印到终端
- 4. 如果想引用结果,需要命令置换符
- 5. 不能做自加和自减
- 6. expr计算乘法时需要使用转义字符
以下是错误的使用方法:
expr V1++
expr 2*3 #运算符两侧要有空格,否则当做字符串
expr 2 * 3 #乘法不使用转义字符,会报错
expr 2 \* 3 #正确的乘法
(4)expr的其他用法
expr match 源字符串 子字符串
在源字符串中查找子字符串
如果源字符串中的,第一个字符和子字符串不相等结果为0
如果子字符串,有字符和源字符串中的字符不相等,返回的也是0.
否则返回的就是子字符串的长度。
#必须是从起点开始匹配 成功才返回长度
string=“www.hqyj.com.hqyj.com.qwer”
string2=“com”
string3=“www.hy”
string4=“www.hq”
expr match $string $string2 #0
expr match $string $string3 #0
expr match $string $string4 #6
expr substr
string=“www.hqyj.com.hqyj.com.qwer”
expr substr $string 5 4 #hqyj
在string中截取从第5个字符开始,向后的4个字符
expr index
#提取指定字符的下标,单个字符有意义,如配置文件:
string=“my_file=/etc/passwd”
num=`expr index $string “=”`
file_path=${string:$num}
echo $file_path
tail -5 $file_path
#多个字符意义不大,如下说明
string=“www.hqyj.com.hqyj.com.qwer”
expr index $string “qy” #6
expr index $string “pqy” #6
拿p字符在string查找第一次出现的位置,如果
找到了就返回它在字符串中的下标,然后结束,
否者找不到接着拿q字符在string查找第一次位置
如果找到返回q在字符串中的下标,否则返回0
expr length
expr length $string
获取string变量字符串的长度 等价于 ${#string}
4. let
let 表达式1 表达式2 … 表达式n #中间用空格分隔
A=2
let C=$A*3
echo '$A*3='$C
let C=A*3
echo 'A*3='$C
输出:
- 注:
-
- let必须是完整的算术表达式,即有等号两边
如let C=A+B
正确
C=`let A+B` 错误
- let必须是完整的算术表达式,即有等号两边
-
- let会运算所有的表达式
VAR1=30
VAR2=25
let RET=VAR1+VAR2 RET=RET+VAR1
echo $RET #85
- let会运算所有的表达式
-
- let中变量可以加$,也可以不加$
-
- 运算符的前后不能加空格,以空格分隔多个表达式
以下为错误用法:
① 运算符加空格报错
A=2
let C=$A * 3
echo '$A*3='$C
② 非完整算数运算表达式
A=2
C=let $A*3
echo $C