Shell
脚本的执行方式
echo
echo "hello world" 输出helloworld-n 不换行显示-e 支持控制字符

shell脚本的执行
# vim hello.sh #创建脚本文件#!/bin/bash #第一行写入该字段,才算是shell脚本echo "hello world"# chmod +x hello.sh #添加执行权限#./hello.sh #执行脚本
Bash的基本功能
history 历史命令
查看历史命令
history -c 清空历史命令history -w 将缓存的历史命令,记录到历史命令文件中
注意:如果用户不退出,历史命令是不会被计入到历史文件中的。
历史命令的调用
上下 调用之前的历史命令
!n 重复第n条命令
!! 重复执行上一条命令
!字串 重复执行最后一条以该字串开头的命令
!$ 重复上一条命令的最后一个参数
alias 命令别名
alias 别名 = ‘原命令’想要永久保存,需要写在 .bashrc 中
Bash常用快捷键


命令行开头|命令行尾|终止|清屏|删除/剪切|删除剪切之后|粘贴剪切内容|搜索|退出终端|暂停放入后台|暂停屏幕输出|恢复屏幕输出
输出重定向

wc 统计
wc 123.txt #统计行数——字数——字节数——文件名wc -c 123.txt #只统计文件字节数
-c 统计字节数
-w 统计单词数
-l 统计行数
管道符
grep 行提取命令
-A 数字 列出符合条件的行,并且列出后续的n行
-B 数字 列出符合条件的行,并且列出前面的n行
-c 统计找到符合条件的字符串的次数
-i 忽略大小写
-n 输出行号
-v 反向查找
—color=auto 搜出的关键字用颜色显示
grep "/bin/bash" /etc/passwdgrep -A 3 "root" /etc/passwd #查找包含有“root”的行,并列出后续的 3 行grep -n "/bin/bash" /etc/passwd #查找可以登录的用户,并显示行号
bash中特殊符号

- 单引号,双引号和反引号
单引号:单引号里写了啥,就输出啥。
双引号:其中的变量,引用等操作都能被显示出来。
反引号:如果是命令,则会执行命令
- 小括号,中括号和大括号
说括号之前,先明白父shell和子shell。每次bash都会创建了bash,可以通过pstree查看
()执行一串命令时,需要重新开一个子 shell 进行执行
{}执行一串命令时,是在当前 shell 执行;
()和{}都是把一串的命令放在括号里面,并且命令之间用;号隔开;
()最后一个命令可以不用分号
{}最后一个命令要用分号;
{}的第一个命令和左括号之间必须要有一个空格;
()里的各命令不必和括号有空格;
()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的
所有命令。
bash变量
# test=123# test="$test"456# echo $test123456#叠加变量 test,变量值变成了 123456# test=$(date)# echo $test2018 年 10 月 21 日 星期一 20:27:50 CST
变量的分类 ★
- 用户自定义变量
- 环境变量:有用户自定义的,也有系统自带的。总的来说就是对整个系统生效。环境变量建议大写。
- 位置参数变量:这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的。
- 预定义变量:是 Bash 中已经定义好的变量,变量名不能自定义,变量作用也是固定的。

用户定义变量
错误的定义方法:
test = liaotest=li ao1test=liao
自定义变量的查看与删除
set 查看自定义变量
unset 变量名
环境变量
export age = "18" #定义变量env #查看环境变量unset age #删除变量
PATH
叠加path内容:
echo "$PATH":/root/sh
PS1变量
PS1='[\u@\h:\A \W]\$ '临时生效,配置文件在:/etc/bashrc

LANG语言变量
echo $LANG #输出语系环境locale #直接查询当前语系vim /etc/sysconfig/i18n #修改linux语系vim /etc/locale.conf #centos7中的语言配置文件
位置参数变量

$n
$1 $2 代表执行脚本后面的参数,例如:
./test.sh 123 100
在下面代码里就是相加的意思

$@
类似循环显示,将输入的数字,一个一个输入进来。
vim xunhuan.sh#!/bin/bashx=$@echo x# bash xunhuan.sh 10 11 12 13# 10 11 12 13
$*
将所有的数字参数,看成一个整体
$
所有数字参数的数量。
预定义变量
事先把名称。作用定义好,内容能自定义的变量。
$?
最后一次执行的命令的返回状态,如果这个变量的值为0,证明上一个命令正确执行。如果这个变量的值为非0,证明上一个命令执行不正确。
ls #查看文件echo $? #输出 0sdkasdlksad #随便输入echo $? #输出非0的随机数
$$
当前进程的PID号
$!
read 键盘接收
用来向脚本传送值,类似input,scanner。非常适合给其他用户使用
read -t 10 -p "qwq:" test-p 提示信息: 在等待read输入时,输出提示信息-t 秒数 : read命令会一直等待用户输入,使用此选项可以指定等待时间-n 字符数: read命令只接受指定的字符数,就会执行-s 隐藏输入的数据:适用于输入机密信息#!/bin/bashread -t 30 -p "请输入数字1:" num1read -t 30 -p "请输入数字2:" num2sum=$((num1+num2))echo $sum
shell运算符
declare声明变量类型

declare [+/-] [选项] 变量名declare -i c=$a+$b #声明变量是整数型,并且是a+b的和declare -r test=123 #设置为只读属性,不能添加删除,修改。declare -e JAVA_HOME=/root/url #设置环境变量
expr和let数值运算工具
a=11b=22d=$(expr $a + $b) # + 两边必须有空格 不然会变成字符型33let e=$a+$b33
使用$((运算符))或 $[运算符](不推荐) ★
a=11b=22f=$(($a+b$)) #此时内部有没有空格都无所谓33
简易的计算机
#!/bin/bashread -t 10 -p "请输入第一个数字: " num1 #10秒内,读取键盘的输入,根据提示信息read -t 10 -p "请输入第二个数字: " num2read -t 10 -p "请输入运算符: " ope #获取输入的运算符#如果ope为指定运算符,然后打印计算结果,并且停止程序[ "$ope" == "+" ] && echo "$(($num1 + $num2))" && exit[ "$ope" == "-" ] && echo "$(($num1 - $num2))" && exit[ "$ope" == "*" ] && echo "$(($num1 * $num2))" && exit[ "$ope" == "/" ] && echo "$(($num1 / $num2))" && exitecho "请输入正确的运算符" #如果运算符有问题,则输出该命令
变量的测试与内容的更换

环境变量配置文件
source 配置文件 #刷新配置文件

1,2,5个是全局的,3,4个是当前用户的。
~/.bash_logout
该文件默认不会写入任何内容,但是有时候我们希望在退出时执行一些操作,就可以在该文件写入命令,比如备份数据,保存数据等。
shell登录信息
/etc/issue
在本地终端登录时,提示的欢迎界面,我们可以自行修改。建议额外添加一个\t和\l即可。


/etc/issue.net
上面那个是本地终端的登录提示,我们常常用ssh登录,所以需要在这个文件中修改才能看到提示。并且还需要在/etc/ssh/sshd_config中加入如下内容才能提示:
cat /etc/ssh/sshd_config#Banner noneBanner /etc/issue.net #将前面的注释去掉,并且添加路径即可。
/etc/motd
这个文件就没有任何限制了,设置了后本地和远程终端都能使用。一般用来填写欢迎信息等提示信息的。
shell正则表达式

首先给grep命令添加匹配颜色
vi /root/.bashrcalias grep = 'grep --color=auto'
常见简单的匹配原则
grep "a*" liao.txt#查询所有的字符任意多次grep "aa*" liao.txt#查询带有a的行grep "aaa*" liao.txt#查询带有两个a以上的行grep "s..d" liao.txt#在s和d之间有两个字符的行grep "^M" liao.txt#以M开头的行grep "N$" liao.txt#以大写N结尾的行grep "s[ao]id" liao.txt#在s和id之间,有a或者o的行grep "[0-9]" liao.txt#查询匹配任意一个数字grep "[A-Z]" liao.txt#匹配A-Zgrep "[^a-zA-Z]" liao.txt#匹配除了英文以外的任意一个字符
更难一些的匹配原则
grep "a\{3\}" liao.txt#匹配出现3次a的行grep "1[0-9]\{10,\}" liao.txt#匹配1之后任意数字出现10次的行 (电话号)grep "tes\{1,4\}t" liao.txt#匹配te和t之间,s出现1到4次的行
扩展正则

其实正则表达式中本来就有这四个字符,只是shell觉得linux中可能很少用到,就把他分隔开了,实际用法并没啥变换。
grep -E "lia+o" liao.txt#匹配liao,并且a可以无限多,只要他有grep -E "liao?1" liao.txt#匹配liao1,或者是lia1grep -E "liao|wuhu" liao.txt#匹配包含liao和wuhu的行grep -E "liao is (geji|ba)" liao.txt#会匹配 liao is geji 或者 liao is ba
字符串处理值${}
1.获取字符串长度
# VAR="hello world"# echo $VARhello world# echo ${#VAR}12
2.字符切片
格式:
${parameter:offset}
${parameter:offset:length}
截取从 offset 个字符开始,向后 length 个字符。
# VAR='HELLO WORLD!'# echo ${VAR:0:5}HELLO #截取前五个字符# echo ${VAR:(-1)}! #截取末尾的字符echo ${VAR:(-2)}D! #截取末尾两个字符# echo ${VAR:(-3):2}LD
3.替换字符串
格式:${parameter/pattern/string}
# VAR='hello world world!'将第一个 world 字符串替换为 WORLD:# echo ${VAR/world/WORLD}hello WORLD world!将全部 world 字符串替换为 WORLD:# echo ${VAR//world/WORLD}hello WORLD WORLD!替换正则匹配为空:# VAR=123abc# echo ${VAR//[^0-9]/} #去掉所有的字母123# echo ${VAR//[0-9]/} #去掉所有的数字abc
patterm 前面开头一个正斜杠为只匹配第一个字符串,两个正斜杠为匹配所有字符。
4.字符串提取
格式:${parameter#word} # 删除匹配前缀${parameter##word}${parameter%%word} # 删除匹配后缀${parameter%%word}
去掉左边,最短匹配模式,##最长匹配模式。
% 去掉右边,最短匹配模式,%%最长匹配模式。
# URL="http://www.baidu.com/baike/user.html"以//为分隔符截取右边字符串:# echo ${URL#*//}www.baidu.com/baike/user.html以/为分隔符截取右边字符串:# echo ${URL##*/}user.html以//为分隔符截取左边字符串:# echo ${URL%%//*}http:以/为分隔符截取左边字符串:# echo ${URL%/*}http://www.baidu.com/baike以.为分隔符截取左边:# echo ${URL%.*}http://www.baidu.com/baike/user以.为分隔符截取右边:# echo ${URL##*.}html
5.变量状态赋值
${VAR:-string} 如果 VAR 变量为空则返回 string
${VAR:+string} 如果 VAR 变量不为空则返回 string
${VAR:=string} 如果 VAR 变量为空则重新赋值 VAR 变量值为 string
${VAR:?string} 如果 VAR 变量为空则将 string 输出到 stderr
如果变量为空就返回 hello world!:# VAR=# echo ${VAR:-'hello world!'}hello world!如果变量不为空就返回 hello world!:# VAR="hello"# echo ${VAR:+'hello world!'}hello world!如果变量为空就重新赋值:# VAR=# echo ${VAR:=hello}hello# echo $VARhello如果变量为空就将信息输出 stderr:# VAR=# echo ${VAR:?这没变量啊}-bash: VAR: 这没变量啊
6.字符串颜色
字体颜色:
30:黑
31:红
32:绿
33:黄
34:蓝色
35:紫色
36:深绿
37:白色
字体背景颜色
40:黑
41:深红
42:绿
43:黄色
44:蓝色
45:紫色
46:深绿
47:白色
显示方式
0:终端默认设置
1:高亮显示
4:下划线
5:闪烁
7:反白显示
8:隐藏
格式:
\033[1;31;40m # 1 是显示方式,可选。31 是字体颜色。40m 是字体背景颜色。
\033[0m # 恢复终端默认颜色,即取消颜色设置。
shell表达式与运算符
1.条件表达式
| 表达式 | 示例 |
|---|---|
| [ expression ] | [ 1 -eq 1 ] |
| [[ expression ]] | [[ 1 -eq 1 ]] |
| test expression | test 1 -eq 1 ,等同于[] |
2.整数比较符
| 比较符 | 描述 | 示例 |
|---|---|---|
| -eq,equal | 等于 | [ 1 -eq 1 ]为 true |
| -ne,not equal | 不等于 | [ 1 -ne 1 ]为 false |
| -gt,greater than | 大于 | [ 2 -gt 1 ]为 true |
| -lt,lesser than | 小于 | [ 2 -lt 1 ]为 false |
| -ge,greater or equal | 大于等于 | [ 2 -ge 1 ]为 true |
| -le,lesser or equal | 等于小于 | [ 2 -le 1 ]为 false |
3.字符串比较符
| 运算符 | 描述 | 示例 |
|---|---|---|
| == | 等于 | [ “a” == “a” ]为 true |
| != | 不等于 | [ “a” != “a” ]为 false |
| > | 大于序 | 在[]表达式中:[ 2 > 1 ]为 true |
| < | 小于 | 在[]表达式中:[ 2 < 1 ]为 false |
| >= | 大于等于 | 在(())表达式中:(( 3 >= 2 ))为 true |
| <= | 小于等于 | 在(())表达式中:(( 3 <= 2 ))为 false |
| -n | 字符串长度不等于 0 为真 | VAR1=1;VAR2=”” [ -n “$VAR1” ]为 true |
| -z | 字符串长度等于 0 为真 | [ -z “$VAR1” ]为 false |
| str | 字符串存在为真 | [ $VAR2 ]为 false |
需要注意的是,使用-z 或-n 判断字符串长度时,变量要加双引号。
举例:
$a=1# [ -z $a ] && echo yes || echo noyes# [ -n $a ] && echo yes || echo noyes# 加了双引号才能正常判断是否为空# [ -z "$a" ] && echo yes || echo noyes# [ -n "$a" ] && echo yes || echo nono# 使用了双中括号就不用了双引号# [[ -n $a ]] && echo yes || echo nono# [[ -z $a ]] && echo yes || echo noyes
4.文件测试
| 测试符 | 描述 | 示例 |
|---|---|---|
| -e | 文件或目录存在为真 | [ -e path ] path 存在为 true |
| -f | 文件存在为真 | [ -f file_path ] 文件存在为 true |
| -d | 目录存在为真 | [ -d dir_path ] 目录存在为 true |
| -r | 有读权限为真 | [ -r file_path ] file_path 有读权限为 true |
| -w | 有写权限为真 | [ -w file_path ] file_path 有写权限为 true |
| -x | 有执行权限为真 | [ -x file_path ] file_path 有执行权限为 true |
| -s | 文件存在并且大小大于 0 为真 | [ -s file_path ] file_path 存在并且大小大于 0 为 true |
5.布尔运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
| ! | 非关系,条件取反 | [ ! 1 -eq 2 ]为 true |
| -a | 和关系,在[]表达中使用 | [ 1 -eq 1 -a 2 -eq 2 ]为 true |
| -o | 或关系,在[]表达中使用 | [ 1 -eq 1 -o 2 -eq 1 ]为 true |
6.逻辑判断符
| 判断符 | 描述 |
|---|---|
| && | 逻辑和,在[[]]和(())表达式中 或判断表达式是否为真时使用 |
| || | 逻辑或,在[[]]和(())表达式中 或判断表达式是否为真时使用 |
示例:
[[ 1 -eq 1 && 2 -eq 2 ]]为 true(( 1 == 1 && 2 == 2 ))为 true[ 1 -eq 1 ] && echo yes 如果&&前面表达式为 true 则执行后面的[[ 1 -eq 1 || 2 -eq 1 ]]为 true(( 1 == 1 || 2 == 2 ))为 true[ 1 -eq 2 ] || echo yes 如果||前面表达式为 false 则执行后面的
7.特殊运算工具
| 命令 | 描述 |
|---|---|
| let | 赋值并运算,支持++、— |
| expr | 乘法*需要加反斜杠转义 |
| bc | 计算器,支持浮点运算、 平方等 |
示例:
let VAR=(1+2)*3 ; echo $VARlet x++;echo $x #每执行一次 x 加 1let x+=2 #每执行一次 x 加 2expr 1 \* 2 #运算符两边必须有空格expr length "string" #获取字符串长度expr index "string" str #获取字符在字符串中出现的位置expr match "string" s.* #获取字符串开始字符出现的长度echo "1.2+2" |bcecho "10^10" |bcecho 'scale=2;10/3' |bc #保留两位小数点[ $(echo "2.2 > 2" |bc) -eq 1 ] && echo yes || echo no
8.shell括号用途
| 括号样式 | 用途 |
|---|---|
| () | 优先计算|数组|匹配分组 |
| (()) | 表达式,只支持>,<,<=,||,&&,不支持-eq |
| $() | 执行shell命令,与反撇号等效 |
| $(()) | 简单算数运算|支持三目运算 |
| [] | 条件表达式,里面不支持逻辑判断符 |
| [[]] | 条件表达式,只支持>,<,<=,||,&&,不支持-eq。支持=~模式匹配,也可以不用双引号也不会影响原意,比[]更加通用 |
| $[] | 简单算数运算 |
| {} | 对逗号(,)和点点(…)起作用,比如 touch {1,2}创建 1 和 2 文件,touch {1..3}创建 1、2 和 3 文件 |
| ${} | 引用变量|字符串处理 |
9.shell流程控制
格式:if list; then list; [ elif list; then list; ] … [ else list; ] fi
单分支
if 条件表达式; then命令fi
示例:
#!/bin/bashN=10 #设置变量if [ $N -gt 5 ]; then #如果N大于5则echo yes #输出 yesfi
双分支
if 条件表达式; then命令else命令fi
示例1:
#!/bin/bashN=10if [ $N -lt 5 ]; then #如果10小于5echo yes #正确了输出yeselseecho no #要么输出nofi
示例 2:判断 crond 进程是否运行
#!/bin/bashNAME=cround #进程名称NUM=$(ps -ef |grep $NAME |grep -vc grep)#查看全部进程|搜索进程并打印|输出除了grep意外的全部进程(此时就是cround+grep,所以需要用到-vc)if [ $NUM -eq 1 ]; then #如果等于1echo "$NAME running" #正在运行elseecho "$NAME not running"fi
示例3:检查主机是否存活
/dev/null 为一个黑洞文件,你输入任何信息,都无法保存。
#!/bin/bashif ping -c 1 58.247.214.47 >/dev/null; then#将ping的消息输入到/dev/null中,命令成功则为yesecho "ok"elseecho "NO"fi
if 语句可以直接对命令状态进行判断,就省去了获取$?这一步!
多分支
if 条件表达式; then命令elif 条件表达式; then命令else命令fi
当不确定条件符合哪一个时,就可以把已知条件判断写出来,做相应的处理。
示例1:
#!/bin/bashread -t 30 -p "输入您的成绩:" Nif [ $N -ge 95 ]; thenecho "您的成绩:优!"elif [ $N -ge 85 ]; thenecho "您的成绩:良!"elif [ $N -ge 75 ]; thenecho "您的成绩:一般!"elseecho "您的成绩太差了"fi
示例 2:根据 Linux 不同发行版使用不同的命令安装软件
#!/bin/bashif [ -e /etc/redhat-release ]; thenyum install vim -yelif [ $(cat /etc/issue | cut -d'' -f1) == "Ubuntu"]; thenapt-get instann wget -yelseecho "您不是Centos或者Ubuntu系统"fi
for语句
格式:for name [ [ in [ word … ] ] ; ] do list ; done
for 变量名 in 取值列表; do命令done
示例:
#!/bin/bashfor i in {1..3}; doecho $idone
或者这样写:
#!/bin/bashfor i in "$@"; { # $@是将位置参数作为单个来处理echo $i}bash for2.sh 1 23 343 51233435
默认 for 循环的取值列表是以空白符分隔
#!/bin/bashfor i in 12 34; doecho $idone# bash test.sh1234
如果想指定分隔符,可以重新赋值$IFS 变量:
#!/bin/bashOLD_IFS=$IFSIFS=":"for i in $(head -1 /etc/passwd); doecho $idoneIFS=$OLD_IFS # 恢复默认值# bash test.shrootx00root/root/bin/bash
for 循环还有一种 C 语言风格的语法,常用于计数、打印数字序列: for (( expr1 ; expr2 ; expr3 )) ; do list ; done
#!/bin/bashfor ((i=1;i<=5;i++)); do # 也可以 i--echo $idone
示例 1:检查多个主机是否存活
#!/bin/bashfor ip in 192.168.128.{1..254}; do #将ip赋值1到254if ping -c 1 $ip > /dev/null; then #如果成功打印echo "$ip OK"elseecho "$ip NO"fidone
示例 2:检查多个域名是否可以访问
#!/bin/bashURL="www.baidu.com www.sina.com www.jd.com"for url in $URL; doHTTP_CODE=$(curl -o /dev/null -s -w %{http_code} http://$url)#通过安静模式(-s)将输出信息打印到/dev/null(-o),打印http状态码(-w)if [ $HTTP_CODE -eq 200 -o $HTTP_CODE -eq 301 ]; then#如果状态码为200或者301则为trueecho "$url OK."elseecho "$url NO!"fidone
while语句
格式:while list; do list; done
while 条件表达式; do命令done
示例1:
#!/bin/bashN=0while [ $N -lt 5 ]; doecho $Nlet N++done
当条件表达式为 false 时,终止循环。
示例 2:条件表达式为 true,将会产生死循环
#!/bin/bashwhile true; doecho "yes"done
还可以条件表达式用冒号,冒号在 Shell 中的意思是不做任何操作。但状态是 0,因此为 true:
#!/bin/bashwhile :; doecho "yes"done
示例 3:逐行处理文本
要想使用 while 循环逐行读取 a.txt 文件,有三种方式:
# cat a.txta b c1 2 3x y z
方式1:
#!/bin/bashcat ./a.txt | while read LINE; doecho $LINEdone
方式2:
#!/bin/bashwhile read LINE; doecho $LINEdone < ./a.txt
方式3:
#!/bin/bashexec < ./a.txt # 读取文件作为标准输出while read LINE; doecho $LINEdone
与 while 关联的还有一个 until 语句,它与 while 不同之处在于,是当条件表达式为 false 时才循 环,实际使用中比较少,这里不再讲解。
break和continue
break 是终止循环。 continue 是跳出当前循环。
示例1: break
#!/bin/bashN=0while true; dolet N++ #n加1if [ $N -eq 5 ]; then #如果N等于5了break #跳出循环fiecho $Ndone
示例2:continue
#!/bin/bashN=0while [ $N -lt 5 ]; do #当N小于5let N++ #N加1if [ $N -eq 3 ]; then #如果等于3continue #跳过fiecho $Ndone
注意:continue 与 break 语句只能循环语句中使用。
case语句
case 语句一般用于选择性来执行对应部分块命令。
格式:case word in [ [(] pattern [ | pattern ] … ) list ;; ] … esac
case 模式名 in模式 1)命令;;模式 2)命令;;*)不符合以上模式执行的命令esac
每个模式必须以右括号结束,命令结尾以双分号结束。
示例1:
#!/bin/bashcase $1 in #给输入的第一个字符赋值start) #如果为startecho "start.";;stop) #如果为stopecho "stop.";;restart)#如果为restartecho "restart.";;*) #如果都不是echo "Usage: $0 {start|stop|restart}" #$0脚本名称esac
上面例子是不是有点眼熟,在 Linux 下有一部分服务启动脚本都是这么写的。
模式也支持正则,匹配哪个模式就执行那个:
#!/bin/bashcase $1 in[0-9])echo "This is Number";;[a-z])echo "This is letter";;'-h'|'--help')echo "help";;*)echo "Input error"exitesac
select语句
select 是一个类似于 for 循环的语句。
格式:select name [ in word ] ; do list ; done
select 变量 in 选项 1 选项 2; dobreakdone
示例1:
#!/bin/bashselect mysql_version in 5.1 5.6; doecho $mysql_versiondone
用户输入编号会直接赋值给变量 mysql_version。作为菜单用的话,循环第二次后就不再显示菜单 了,并不能满足需求。
示例2:
#!/bin/bashwhile true; do #一直循环select mysql_version in 5.1 5.6; doecho $mysql_version #输出字符break #停止select循环donedone
如果再判断对用户输入的编号执行相应的命令,如果用 if 语句多分支的话要复杂许多,用 case 语 句就简单多了。
#!/bin/bashPS3="选择虚拟机编号:" #更换界面提示符while true; doselect mysql in 5.1 5.6; docase $mysql in5.1)echo "mysql 5.1"break;;5.6)echo "mysql 5.6"break;;quit)echo "quit bye!"exit;;*)echo "error!!!!!"breakesacdonedone
如果不想用默认的提示符,可以通过重新赋值变量 PS3 来自定义。这下就比较完美了!
数组与函数
1.函数
格式:
func() {command}
function 关键字可写,也可不写。
示例1:
#!/bin/bashfunc(){echo "This is a function"}func #调用函数func #调用函数
Shell 函数很简单,函数名后跟双括号,再跟双大括号。通过函数名直接调用,不加小括号。
示例2:函数返回值
#!/bin/bashfunc(){VAR=$((1+1))return $VARecho "This is a function"}funcecho $? #输出上一个指令的返回值
return 在函数中定义状态返回值,返回并终止函数,但返回的只能是 0-255 的数字,类似于 exit。
示例3:函数传参
#!/bin/bashfunc(){echo "hello $1"}func world
通过 Shell 位置参数给函数传参。
函数也支持递归调用,也就是自己调用自己。
示例:
#!/bin/bashtest(){echo $1sleep 1test hello}test
执行会一直在调用本身打印 hello,这就形成了闭环。
像经典的 fork 炸弹就是函数递归调用: :(){ :|:& };: 或 .(){.|.&};.
这样看起来不好理解,我们更改下格式:
:() {:|:&};:bomb() {bomb|bomb&};bomb
分析下:
:(){ } 定义一个函数,函数名是冒号。
: 调用自身函数
| 管道符
: 再一次递归调用自身函数
:|: 表示每次调用函数”:”的时候就会生成两份拷贝。
& 放到后台
; 分号是继续执行下一个命令,可以理解为换行。
: 最后一个冒号是调用函数。
因此不断生成新进程,直到系统资源崩溃。 一般递归函数用的也少,了解下即可!
2.数组
数组是相同类型的元素按一定顺序排列的集合。
格式: array=(元素 1 元素 2 元素 3 …)
用小括号初始化数组,元素之间用空格分隔。
定义方法 1:初始化数组 array=(a b c)
定义方法 2:新建数组并添加元素 array[下标]=元素
定义方法 3:将命令输出作为数组元素 array=($(command))
数组操作:
获取所有元素:# echo ${array[*]} # *和@ 都是代表所有元素a b c获取元素下标:# echo ${!a[@]}0 1 2获取数组长度:# echo ${#array[*]}3获取第一个元素:# echo ${array[0]}a获取第二个元素:# echo ${array[1]}b获取第三个元素:# echo ${array[2]}c添加元素:# array[3]=d# echo ${array[*]}a b c d添加多个元素:# array+=(e f g)# echo ${array[*]}a b c d e f g删除第一个元素:# unset array[0] # 删除会保留元素下标# echo ${array[*]}b c d e f g删除数组:# unset array
示例 1:讲 seq 生成的数字序列循环放到数组里面
#!/bin/bashfor i in $(seq 1 10); doarray[a]=$ilet a++doneecho ${array[*]}
示例2:遍历数组元素
#!/bin/bashIP=(192.168.1.1 192.168.1.2 192.168.1.3)for ((i=0;i<${#IP[*]};i++)); doecho ${IP[$i]}done#!/bin/bashIP=(192.168.1.1 192.168.1.2 192.168.1.3)for IP in ${IP[*]}; doecho $IPdone
字符串截取和替换命令
1.cut
列提取命令
cut [选项] 文件名
-f 列号: 提取第几列
-d 分隔符: 按照指定分隔符分割列
-c 字符范围:不依赖分隔符来区分列,而是通过字符范围(行首为 0)来进行字段提取
示例:1
ID Name gender Mark1 liao M 802 wuhu W 503 gouzi M 69
命令
cut -f 2 liao.txt #提取第二列内容cut -f 2,3 liao.txt #提取第二第三列的内容cut -d ":" -f 1,3 /etc/passwd #以:作为分隔符,提取/etc/passwd文件的第一列和第三列grep "/bin/bash" /etc/passwd | grep -v "root" | cut -d ":" -f 1#查询passwd文件中的普通用户
