Shell编程基础
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell编程基础相关的知识,希望对你有一定的参考价值。
Shell编程
一.程序简介
程序
程序:算法+数据结构
数据结构:数据在计算机中的类型和组织方式
算法:处理数据的方式
面向过程:以指令为中心,数据服务于指令
面向对象:以数据为中心,指令服务于数据
计算机:二进制执行
高级编程语言:
编译:高级语言->编译器->机器代码->执行
解释:高级语言->执行->解释器->机器代码 shell
三大逻辑
顺序、循环、选择
二.shell脚本
1.格式
格式要求:首行shebang机制
#!/bin/bash 指定shell类型
# 注释
程序名,作用说明,版本信息,作者信息
bash -n 检查语法错误
bash -x 跟踪调试脚本的执行过程
2.变量
变量的类型:
字符、整型
强类型
弱类型
不需要声明变量类型
不支持浮点型
都以字符串的形式存储
命名规则:
不能是内部命令、系统关键字
字母、数字、下划线
不能以数字开头
定义变量
a=linux
a=‘linux‘
a="linux"
上面三个都是把linux这个字符串赋值给变量a,如果赋值的一方当中没有空格,则不用引号,如果有空格则必须用引号。
使用变量
echo $a
echo ${a}
调用变量a,在变量前面加上$即可,变量用{}括起来是个良好的习惯
已经定义的变量也可以重新赋值
a=centos
unset a 删除变量
readonly a 只读变量,不能修改
单双引号的区别
单引号 ‘‘ 强引用,单引号里所有内容都作为字符输出
双引号 "" 若引用,双引号里有变量的时候,会读取变量值输出,而不是直接输出
把命令执行结果赋值给变量
a=`cat /etc/fstab` 使用反向单引号
a=$(cat /etc/fstab) 使用$()
反向单引号容易和单引号混淆,因此推荐使用$()
局部变量和全局变量
局部变量:生效范围是当前shell进程
全局变量:生效范围是当前shell及其子进程
export a 声明全局变量
set 显示变量,自定义和系统自带的
export 或 declare 显示环境变量
echo $PPID 显示父进程编号
pstree -p 显示进程信息
source 运行的脚本在本bash环境下,会修改某些当前bash下的环境。
bash 运行脚本时会新开一个bash,为当前bash的子进程,不会影响当前环境
SHLVL 变量,shell 的嵌套深度
echo $_ 上一个命令的最后一个字符串
unset name 删除变量,除了只读变量
readonly 查看只读变量 declare -r
(umask=0022;touch a)
() 不开启子进程
{} 开启子进程
位置变量
$$ 当前shell的ID
$1 第一个参数
$* 所有参数,认为所有参数是一个整体
[email protected] 所有参数,认为所有参数是独立的个体
$# 参数数量
$0 当前脚本的文件名
10以上的加{}
shift n 变量按顺序往前移动n个变量
set -- 清除变量
退出状态
$? 变量保存最近(前一个)的命令退出状态
0 代表成功,1-255 代表失败
脚本里指定返回值 exit 10
2.运算
bash支持算术运算、关系运算、布尔运算、字符串运算和文件测试运算等
算术运算
expr 2 + 4
echo `expr 2 + 4
a=`expr 2 + 4`
c=`expr $a + $b`
expr是一款表达式计算工具,数值和运算符之间必须有空格,调用整个表达式的时候记得加``
let sum=x+y
$[x+y]
$((x+y))
expr 2 + 3 expr是一个命令
declare -i n=10 指定n是个整数,声明变量
-= += -- ++
运算符 | 说明 | 举例 |
---|---|---|
+ | 加法 | `expr $a + $b |
- | 减法 | `expr $a - $b |
* | 乘法 | `expr $a * $b |
/ | 除法 | `expr $a / $b |
% | 取余 | `expr $a % $b |
= | 赋值 | a=$b |
== | 比较两个数字是否相等 | [ $a == $b ] |
!= | 比较两个数是否不等 | [ $a != $b ] |
表达式和[ ]之间需要有空格
逻辑运算
true 1 ;false 0;
与 & 有0即0
或 | 有1即1
非 ! 取反
短路与 && 前一个为假则不再判断第二个
短路或 || 前一个为真则不再判断第二个
异或 ^ 相同为假,相异为真
同或 相同为真,相异为假
测试命令:
test 不支持正则表达式,没值就为假,变量加“”
[[]] 支持正则表达式
[] 有值就为真
[] 和变量之间要加空格
几种括号的用法
(; ; ) 几个命令一起执行,开启子shell
{; ; } 几个命令一起执行,不开启子shell,前后空格,最后一个加;号
[] 逻辑判断,不支持正则表达式
[[]] 逻辑判断,支持正则表达式,一般用[]
=~ 匹配,字符串不要加"",支持正则表达式
!= 不等
== 相等,字符串不要加"",支持通配符
关系符运算
数值测试,不支持字符
运算符 | 说明 | 全称 |
---|---|---|
-gt | 是否大于 | greater than |
-ge | 是否大于等于 | greater than equal |
-eq | 是否等于 | equal |
-ne | 是否不等于 | no equal |
-lt | 是否小于 | less than |
-le | 是否小于等于 | less equal |
字符串测试
= 是否等于
> ascii码是否大于
< 是否小于
!= 是否不等于
=~ 左侧字符串是否能够被右侧的pattern匹配,一般用于[[]]中
-z "string" 字符串是否为空,空为真,非空为假
-n "string" 字符串是否不空,不空为真,空位假
文件测试
-a / -e file :文件存在性测试,存在未真,否则为假
-b 是否存在且为块设备文件
-c 是否存在且为字符设备文件
-d 是否存在且为目录文件
-f 是否存在且为普通文件
-h / -L :存在且为链接文件
-p 是否存在且为命名管道文件
-S 是否存在且为套接字文件
权限测试
-r 是否存在且可读
-w 是否存在且可写
-x 是否存在且可执行
-u 是否存在且拥有suid权限
-g 是否存在且拥有sgid权限
-k 是否存在且拥有sticky权限
文件属性
-s 是否存在且为非空
-t 文件描述符是否在某终端打开
-N 文件自从上一次被读取之后是否被修改
-O 当前有效用户是否为文件时属主
-G 当前用户是否为文件属组
双目测试
file1 -ef file2:1是否是2的硬链接
file1 -nt file2:1是否新于file2
file1 -ot file2:1是否旧于file2
-a 并且
-o 或者
! 非
3.字符串
单引号
str=‘this is a string‘
单引号里的任何字符都会原样输出,单引号里的变量是无效的
单引号字符串中不能出现单引号,对单引号转义后也不行
双引号
str="you name is $name"
双引号里可以有变量
双引号里可以出现转义字符
拼接字符串
firstname="zhang"
lastname="hw"
echo $firstname $lastname 输出:zhanghw
获取字符串长度
str="abcd"
echo ${#str} 输出:4
提取子字符串
str="daxiong is the best girl"
echo ${str:1:4} 1:4 起始字符到终止字符,由0开始
查找子字符串
str="daxiong is the best girl"
echo `expr index "$str" is`
4.数组
只支持一维数组,没有限定数组大小。数组元素下表从0开始,下表可以是整数或算术表达式,其值应大于或等于0
定义
用括号来定义数组,各个元素间用空格分开,如下:
array_name=(value0 value1 value2)
单独定义
array_name[0]=value0
array_name[1]=value1
引用
${array_name[index]}
a=${array_name[0]}
${array_name[@}}
${array_name[*]} @或* 可以获取数组中的所有元素
获取数组的长度
a=${#array_name[@]} 取得数组元素的个数 @或*都可以
a=${#array_name[n]} 取得下标为n的元素的长度
5.shell printf
printf命令用于格式化输出,printf由POSIX标准所定义,移植性比echo好
printf "hello
" 输出字符串,printf不自带换行,需要在字符串最后添加
printf format-string [arguments]
format-string为双引号
$ printf "%d %s
" 1 "abc"
1 ab
格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
$ printf %s abc def
abcdef
$ printf "%s
" abc def
abc
def
$ printf "%s %s %s
" a b c d e f g h i j
a b c
d e f
g h i
j
如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
$ printf "%s and %d
"
and 0
6.if else 语句
- if...fi
- if...else...fi
- if...elif...else...fi
最后必须以fi结尾来闭合
if 语句的用法
if [ expression ]
then
Statement(s) to be executed if expression is true
fi
如果expression返回ture,then后面的语句将会被执行;如果返回false则跳出循环
if..else...fi 语句的用法
if [ expression ]
then
Statement(s) to be executed if expression is true
else
Statement(s) to be executed if expression is not true
fi
如果expression返回true则执行then后面的语句,否则执行else后面的语句
if...elif...fi 语句的用法
if [ expression 1 ]
then
Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
Statement(s) to be executed if expression 2 is true
else
Statement(s) to be executed if no expression is true
fi
哪一个expression 的值为true,就执行那个expression后面的语句,如果都为false则执行else后面的语句
7.for循环
for varibale in 列表
do
command1
command2
...
conmmandN
done
列表是一组数值(数值、字符串等)组成的序列,每个值通过空格分格。每循环一次,就将列表中的下一个值赋给变量
in 列表是可选的,如果不用它,for循环使用命令行的位置参数
seq 列表的产生
wait
8.while循环
-
while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件
while command
do
Statement(s) to be executed if command is true
done
: 代表true的意思
9.until循环
-
直到型循环,当执行结果为true时才跳出循环。
until command
do
Statement(s) to be executed until command is true
done
10.continue
跳过本次循环
> break [N] 直接结束第N层的本轮循环,而直接进入下一轮判断,最内层为第1层,默认值为1
while command1
do
if command2
then
continue
fi
done
11.break
跳出整个循环
break [N] 提前结束第N层循环,最内层为第一层
while command1
do
if command2
then
break
fi
done
12.shift
shift [n]
将参量列表list左移指定次数,缺省为左移一次。列表list一旦被移动,最左端的那个参数就从列表中删除。
#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ]
do
echo "$1"
shift
done
echo
13.select
select variable in list
do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在
标准错误上,并显示 PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
select 是个无限循环,因此要记住用 break 命令退出循环,或用
exit 命令终止脚本。也可以按 ctrl+c 退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量
14.while特殊用法
while read line
do
循环体
done < /path/from/somefile
依次读取/path/from/somelife 文件中的每一行,且将行赋值给变量line
15.case...esac
- case...esca 是一种多分支选择结构
-
case语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令。
case VALUE in
mode1)
command 1
command 2
command 3
;;
mode2)
command1
command2
command3
;;
esac
取值后面必须为关键字in,每一模式必须以右括号结束。取值可以为变量或常数。
;; 与其他语言中的break 类似,意思是跳到整个case语句的最后。
以上是关于Shell编程基础的主要内容,如果未能解决你的问题,请参考以下文章