1、概念
Shell是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务, Shell脚本(shell script),是一种为Shell编写的脚本程序。我们经常说的shell通常都是指shell脚本。
2、脚本输出方法
a、echo [选项] [内容]
当选项为 -e的时候,内容里面出现以上的内容时,就会识别上表中的符号
如 echo -e 'hello' => 输出 helo
echo输出颜色表示:echo -e "e[1;31mthis is test e[0m"
#30m: 黑色 #31m:红色 #32m:绿色 #33m:黄色 #34m:蓝色 #35m:洋红 #36m:青色 #37m:白色
3、脚本的声明
#!/bin/bash //可以用echo $SHELL进行查看 echo 'hello world!'
说明:
#!
告诉系统这个脚本需要什么解释器来执行。- 文件扩展名
.sh
不是强制要求的。 - 方法1 直接运行解释器,
hello.sh
作为 Shell 解释器的参数。此时 Shell 脚本就不需要指定解释器信息,第一行可以去掉。 - 方法2 hello.sh 作为可执行程序运行,Shell 脚本第一行一定要指定解释器。
注意:在shell中常常会看到exit 0 这里的0表示成功退出非0表求错误退出。
4、脚本的运行
// 方法1 sh hello.sh // 方法2 chmod +x hello.sh ./hello.sh
// 方法3
sh hello.sh
5、shell变量
定义:Shell 变量分为系统变量和自定义变量。系统变量有$HOME、$PWD、$USER等,显示当前 Shell 中所有变量:set
。
变量名可以由字母、数字、下划线组成,不能以数字开头。
#!/bin/bash name='testName' //注意:这里是不能有空格的 readonly name //一旦声明了readonly,那么这个为师是只读的,不允许更改 //使用变量 echo $name //或者 echo ${name}
删除变量
#!/bin/bash name='aaa'; readonly name; age=20; unset name; //readonly 的变量是不能被删除 unset age; //可以被删除
注意:变量的定义与变量的删除都不用$符来修饰
通常上面定义的是全局变量,不建议定义全局变量,可以使用局部变量,在变量前面添加local 关键字
# 定义局部变量
function test2(){
local -i a=3 //如果declare与local并在的时候,写法可以省去declare
declare -i b=3
}
6、shell字符串
双引号的字符串拼接
#!/bin/bash name='bill'; age=20; echo -e "e[1;34m 我的名字叫"${name}"我今年"$age"岁了e[0m"; echo -e "e[1;35m 我的名字叫${name},我今年${age}岁了e[0m";
双引号可以解析引号内的内容
your_name='runoob' str="Hello, I know you are "$your_name"! " echo -e $str
单引号的字符串拼接
# 使用单引号拼接 greeting_2='hello, '$your_name' !' greeting_3='hello, ${your_name} !' echo $greeting_2 $greeting_3
获取字符串的长度
#!/bin/bash name="are you ok ???"; echo "name的长度是:${#name}"; echo "name的长度是"`expr length "$name"`;
提取查询的子串的长度
echo `expr match "$name" today` //输出5 echo `expr match $name good` //输出0
注意:这里是需要从第一位开始匹配的
提取子字符串
注意:第三个方法的负数最好有一个空格,或者采用第四种方法,表示的是从左边截取几位数
#!/bin/bash str="bill is super man!"; echo "第二个字符到第六个字符是${str:2:6}"; #输出 第二个字符到第六个字符是ll is echo ${str: -3} //输出 an! 注意中间需要有一个空格 string="abcdefghijklmnopqrstuvwxyz"; echo ${str: -12:3} //输出opq 注意从右边开始算,取正常顺序的3个字符
查找子字符串
查找是从第1位开始,如果没有找到那么就返回0,例如查找ac是先查找a然后再查找c,看哪个先找到,那么就返回先找到的部份,当a与c都能找到的情况下,返回比较小的值
#!/bin/bash str="abcdefghijklmnopqrstuvwxyz"; echo `expr index "$str" s`; echo `expr index "$str" ac`;
注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。
变量替换
举例:
#!/bin/bash str="I see a yellow duck looking at me"; clip1=${str#*a}; clip2=${str##*a}; echo $clip1; //输出 yellow duck looking at me echo $clip2; //输出 t me clip3=${str%a*}; clip4=${str%%a*}; echo $clip3; //输出 I see a yellow duck looking echo $clip4; //输出 I see clip5=${str/a/bb}; clip6=${str//a/bb}; echo $clip5; //输出 I see bb yellow duck looking at me echo $clip6; //输出 I see bb yellow duck looking bbt me
文本练习
#!/bin/bash str="Bigdata process framework is Hadoop, Hadoop is an open source project"; function show_tip() { echo "*******************************"; echo "(1)打印string的长度"; echo "(2)删除字符串中所有的Hadoop"; echo "(3)替换第一个Hadoop为Mapreduce"; echo "(4)替换全部Hadoop为Mapreduce"; echo "*******************************" } function show_len() { echo "string的长度是${#str}"; } function del_str() { echo ${str//Hadoop}; } function rep_str() { echo ${str/Hadoop/Mapreduce}; } function rep_all_str() { echo ${str//Hadoop/Mapreduce}; } while true; do echo "【str=$str】"; show_tip; read -p "请选择对应的操作1|2|3|4|q|Q: " choice case $choice in 1) show_len;; 2) del_str;; 3) rep_str;; 4) rep_all_str;; q|Q) exit;; *) echo "输入有误,请重新输入(1|2|3|4|q|Q)"; esac done
7、数组
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
数组的定义
数组名=(值1 值2 ... 值n)
也可以采用各个项来定义
array_name[0]=value0 array_name[1]=value1 array_name[n]=valuen
输出数组
#!/bin/bash arr=("a" "b" "c" "d"); echo ${arr[0]}; //输出第0项 echo ${arr[@]}; //输出所有项数组
输出数组的长度
#!/bin/bash arr=("aa" "bbb" "cccc" "ddddd"); echo "数组的长度是"${#arr[@]}; //输出4 echo "这个也是数组的长度"${#arr[*]}; //输出4 echo "这个是数组中单项的长度"${#arr[3]}; //输出5
8、函数的定义
函数的定义方式:
$n表示输出第n位参数,$@与$*的意思一样表示输出所有的参数,$#表示参数的个数
#!/bin/bash function func() { echo $1,$@; } func "gaga";
练习:
#!/bin/bash function count { case $2 in +) echo `expr $1 + $3`;; -) echo `expr $1 - $3`;; *) echo `expr $1 * $3`;; /) echo `expr $1 / $3`;; esac } count $1 $2 $3 //调用的时候 sh bash.sh 12 + 2
函数的返回值
return 返回值 只能返回1-255的整数。通常return只是用来供其他地方调用获取状态,因此通常仅返回0或1;0表示成功,1表示失败
echo 返回值可以返回任何字符串结果 。通常echo用于返回数据,比如一个字符串值或者列表值。
#!/bin/bash function getUser { user=$(cat /etc/passwd|cut -d ":" -f 1); echo $user; //返回值是查询结果 } data=`getUser`; for var in $data; do echo $var; done; exit;
9、shell中的read命令
简单读取
#!/bin/bash echo "请输入任意的内容"; read content; //把输入的内容赋值给content这个变量 echo "你输入的内容是"$content;
- -p 后面跟提示信息,即在输入前打印提示信息。
- -t 后面跟秒数,定义输入字符的等待时间。
- -s 安静模式,在输入字符时不再屏幕上显示,例如login时输入密码。
- -n 后跟一个数字,定义输入文本的长度,很实用。
#!/bin/bash read -p "请输入任意的内容:" content; echo "你输入的内容是:"$content;
#!/bin/bash if read -t 5 -p "请5秒内输入用户名:" user; //这里在-t后面跟数据可以有空格,也可以没有空格 then echo "您输入的用户名是:"$user; else echo "对不起,你输入超时"; fi exit 0;
#!/bin/bash read -n1 -p "请选择Y|N" sign //这里的-n后面跟数据可以有空格,也可以没有空格 echo "你输入的是:"$sign;
10、字符串的运算符
使用[[ ... ]]条件判断结构,而不是[ ... ],能够防止脚本中的许多逻辑错误。比如,&&、||、<和> 操作符能够正常存在于[[ ]]条件判断结构中,但是如果出现在[ ]结构中的话,会报错。比如可以直接使用if [[ $a != 1 && $a != 2 ]], 如果不适用双括号, 则为if [ $a -ne 1] && [ $a != 2 ]或者if [ $a -ne 1 -a $a != 2 ]。
#!/bin/bash read -n1 -p "请输入对应的指令Y|N" sign; if [[ $sign = "Y" || $sign = "y" ]] //这里的[[]]的前后都要加上空格,在if后面也要加上空格 then echo "你输入的是肯定的回答"; elif [[ $sign = "N" || $sign = "n" ]] then echo "你输入的是否定的回答"; else echo "输入的字符不合法,请输入Y|N"; fi exit 0;
11、流程控制语句
if...elif...else例子如上
case 语句,相当其他语法的switch
#!/bin/bash num=12; case $num in 1|2|3|4|5|6|7|8|9) echo '这个值是小于10的值';; 10) echo "这个值是等于10的值";; *) echo "这个值是大于10的值";; esac exit 0;
for语名的使用
#!/bin/bash for((i=0; i<=10; i++)); do echo "现在输出的是"${i}; done; exit 0;
注意:这里使用的是双括号
#!/bin/bash arr=("aa" "bb" "cc" "dd" "ee"); for per in ${arr[@]}; do echo "值为"$per; done exit 0;
while的使用
#!/bin/bash int=1 while(( $int<=5 )) do echo $int let "int++" done
注意:这里的Let相当于(())的用法
12、命令替换
#!/bin/bash echo $(date +%Y); echo `date +%Y`; echo "明年是"$((`date +%Y` + 1))"年"; echo "明年是"$(($(date +%Y) + 1))"年";
如果没有命令替换,那么会输出命令
#!/bin/bash //当本机的ngnix进程没有的时候,那么重新启动nginx服务 nginx_process_num = $(ps -ef | grep nginx | grep -v grep | wc-1) //重点表示过滤 if [ $nginx_process_num -eq 0 ]; then systemctl start nginx fi
13、cut的使用
常用命令 cut -d ":" -f 1 表示从字符串中截取一部份 -d:表示自定义分隔符,默认为制表符,“:” 表示以:进行分割, -f:与-d一起使用,指定显示哪个区域。1:表示取第一部份
#!/bin/bash name="this is test are you ok???"; echo $name|cut -d " " -f 1; //输出 this
14、wc的使用
在默认的情况下,wc将计算指定文件的行数、字数,以及字节数。使用的命令为:
wc testfile
- -l或--lines 只显示行数。
- -w或--words 只显示字数。
wc test.sh //输出 6 11 72 bash.sh ls -l|wc -l //输出 3 表示有3条记录
15、bc的使用
bc 命令是任意精度计算器语言,通常在linux下当计算器用。一般来讲,等式的小数位数决定了答案的位数
#!/bin/bash echo "scale=2;3/8" | bc; //输出 0.37 echo "0.356 * 2" | bc; //输出0.712
向上取整与向下取整的函数封装
parseFloat() { echo "$1 + 0.000" | bc } floor() { a=$(parseFloat $1) b=$(parseFloat $2) echo `echo "scale=0; $a/$b" | bc` } ceil() { a=$(parseFloat $1) b=$(parseFloat $2) num=$(echo "scale=2; $a/$b" | bc) int=$(floor $a $b) if [ $(echo "$int < $num"|bc) -eq 1 ]; then echo $(($int+1)) else echo $int; fi } round() { a=$(parseFloat $1) b=$(parseFloat $2) num=$(echo "scale=2; $a/$b" | bc) int=$(floor $a $b) middle=$(echo "$int + 0.5" | bc) if [ $(echo "$middle < $num"|bc) -eq 1 ]; then echo $(($int+1)) else echo $int; fi } echo $(floor 11 3) 3 echo $(floor 12 3) 4 echo $(floor 13 3) 4 echo $(floor 14 3) 4 echo $(ceil 11 3) 4 echo $(ceil 12 3) 4 echo $(ceil 13 3) 5 echo $(ceil 14 3) 5 echo $(round 11 3) 4 echo $(round 12 3) 4 echo $(round 13 3) 4 echo $(round 14 3.3) 4 echo $(round 15 3) 5
16、ps的用法
ps命令 用于报告当前系统的进程状态。可以搭配kill指令随时中断、删除不必要的程序。ps命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。
以下是ps的常用用法
ps axo pid,comm,pcpu # 查看进程的PID、名称以及CPU 占用率 ps aux | sort -rnk 4 # 按内存资源的使用量对进程进行排序 ps aux | sort -nk 3 # 按 CPU 资源的使用量对进程进行排序 ps -A # 显示所有进程信息 ps -u root # 显示指定用户信息 ps -efL # 查看线程数 ps -e -o "%C : %p :%z : %a"|sort -k5 -nr # 查看进程并按内存使用大小排列 ps -ef # 显示所有进程信息,连同命令行 ps -ef | grep ssh # ps 与grep 常用组合用法,查找特定进程 ps -C nginx # 通过名字或命令搜索进程 ps aux --sort=-pcpu,+pmem # CPU或者内存进行排序,-降序,+升序 ps -f --forest -C nginx # 用树的风格显示进程的层次关系 ps -o pid,uname,comm -C nginx # 显示一个父进程的子进程 ps -e -o pid,uname=USERNAME,pcpu=CPU_USAGE,pmem,comm # 重定义标签 ps -e -o pid,comm,etime # 显示进程运行的时间 ps -aux | grep named # 查看named进程详细信息 ps -o command -p 91730 | sed -n 2p # 通过进程id获取服务名称
例如查找linux中nginx的进程 ps -ef| grep nginx | grep -v grep
17、有类型的变量(即类型声明)
在shell中进行变量类型声明,需要通过declare和typeset两个命令进行操作,这两者是等价的, 下在以declare为例:
注意:声明了环境变量后,在脚本中就可以直接使用
取消声明的变量
取消声明的变量
declare +r 取消只读
declare +i 取消只为整型
declare +a 取消只为数组
declare +x 取消只为环境变量
18、bash数学运算之expr
语法:
注意:expr后面每个单语需要有空格,operator表示运算符
注意:在expr运算中,特殊的符号需要加上转义符号
#!/bin/bash num1=100; num2=200; num3=$(expr $num1 + $num2); //使用这种语法,在赋值的时候需要进行转义 num4=`expr $num2 + $num3`; num5=$(($num3 + $num4)); echo $num3; echo $num4; echo $num5;
注意:$(())不是一个表达式,但是可以进行赋值, expr是一个表达式,命令,可以单独运行,所以在expr进行赋值的时候,需要进行命令的替换。
练习:
[root@instance-yvmni62c ~]# cat bash.sh #!/bin/bash info() { echo "********************************************"; echo "输入一个数求和"; echo "********************************************"; } isInt() { num=$(echo "scale=0; $1/1"|bc); echo `expr $num >= $1`; } getTotal() { num=0; for((i=0; i<=$1; i++)); do num=$(($num + $i)); done echo "总和是"$num; } while true do info; read -p "请输入一个数:" count; echo $count; if [ $count -gt 0 ] && [ $(isInt $count) -eq 1 ] then getTotal $count; else echo "输入的数字格式有误"; fi done
判断是否是正整数
#!/bin/bash
read -p "输入一个数 " count;
expr $count + 1 &> /dev/null;
echo $?; //输出0表是是正整数 1是负数 2是小数
19、sleep表示睡眠
sleep(参数)
#!/bin/bash b='' for ((i=0;$i<=100;i++)) do printf "Progress:[%-100s]%d%% " $b $i sleep 0.1 b=#$b done echo
20、find的使用细节
常用选项配置
find命令总结 常用选项: -name 查找/etc目录下以conf结尾的文件 find /etc -name '*conf' -iname 查找当前目录下文件名为aa的文件,不区分大小写 find . - iname aa -user 查找文件属主为hdfs的所有文件 find . -user hdfs -group 查找文件属组为yarn的所有文件 find,- group yarn -type f 文件 find . -type f d 目录 find . -type d c 字符设备文件 find . -type c b 块设备文件 find . -type b l 链接文件 find . -type l p 管道文件 find . -type p
-size -n 大小大于n的文件 +n 大小小于n的文件 n 大小等于n的文件 例子1:查找/etc目录下小于10000字节的文件 find /etc -size -10000c 例子2:查找/etc目录下大于1M的文件 find /etc -size +1M -mtime -n n天以内修改的文件 +n n天以外修改的文件 n 正好n天修改的文件 例子1:查找/etc目录下5天之内修改且以con结尾的文件 find /etc -mtime -5 -name '*.conf' 例子2:查找/etc目录下10天之前修改且属主为xoot的文件 find/etc -mtime +10 -user root
对查找到的结果进行操作
语法 find【路径】【选项】【操作】-exec command {} ;
例子:
练习:
#!/bin/bash if [ ! -d 'abc' ]; then echo "文件夹不存在的哈"; exit; fi function dealFile { cd ~; mkdir -p 'bf/conf'; mkdir -p 'bf/sh'; cd "abc"; find ./ -name "*.conf" -exec mv {} ../bf/conf/ ; wait $! #等待上个命令执行完成 find ./ -name "*.sh" -exec mv {} ../bf/sh ; wait $!; cd ~; rm -rf abc; mv bf abc; cd abc; } #对所对应的两个文件夹进行压缩处理,conf采用bz2压缩,sh采用gz压缩 function packFile { tar -jcvf conf.tar.bz2 ./conf tar -zcvf sh.tar.gz ./sh #删除原有的目录 rm -rf conf sh; }
21、grep与egrep的使用
grep: 是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。用于过滤/搜索的特定字符。可使用正则表达式能多种命令配合使用,使用上十分灵活。
egrep: 用于在文件内查找指定的字符串。egrep执行效果与grep -E
相似,使用的语法及参数可参照grep指令,与grep的不同点在于解读字符串的方法。
grep的语法格式:
◆第一种形式: grep [option] [ pattern] [file1,file2...] 这种形式主要是在文件中查找,遍历文件的每一行,如果有匹配的就把那行列出来;
◆第二种形式: command | grep [option][pattern] 这种形式主要是在命令的终端中进行查找
grep常用的配置选项
grep -r ~/ 表示在~目录下对所有文件进行递归查询,在普通文件下是没有意义的。
22、rpm的使用
rpm命令 是RPM软件包的管理工具。在查询nginx的时候可以使用 rpm -ql nginx来查询相应的信息
23、sed的工作模式
sed:流编辑器。对标准输出或文件逐行进行处理
sed的语法格式:
◆第一种形式: stdout | sed [option] "pattern command"
◆第二种形式:sed [option] "pattern command" file
sed的选项
sed 'p' test.txt //这里的p是个命令表示print的意思 , 原来sed有打印的意思,所以这里会输出2次 sed -n 'p' test.txt // -n表求静默模式,会取消原来默认的打印模式,所以只会打印一次 sed -n '/day/p' test.txt // 这里的day表示查询匹配的意思,后面的p表示print(以行为单位进行匹配),也可以是day.*表示匹配day后面有的所有字符
-e可以理解成或的关系,如果有有一个可以不写,但是有多个就都要写
sed -n -e '/day/p' -e '/ok/p' test.txt //表示输出含day,也输出含有ok的行
-f可以理解为file,例如新建一个文件key.txt里面的内容是 /ok/p
sed -n -f key.txt test.txt //表示把key.txt中的内容拿到test.txt中进行匹配
-r表示正则表达式
sed -n -r '/ok|day/p' test.txt
-i表示修改文件内容
sed -n -i 's/day/today/g;p' test.txt //表示把文中的day 改成today;p表示输出(可省),如果没有-i那么只是把改的结果输出给你,原文不更改,加-i后会更改原文件
set中的pattern祥解表示匹配模式
30、$()与${}, $(()), []的区别
shell中要对一个命令的结果做操作这时候就要用到$(),但是如果只对一个变量做操作的时候就要用到${}
$(())
是用来作整数运算的。在bash中, $(())
的整数运算符号大致有这些:
- +- * / #分别为”加、减、乘、除”。
- % #余数运算,(模数运算)
- & | ^ ! #分别为”AND、OR、XOR、NOT”运算。
[ ] :即为test命令的另一种形式。
但要注意许多:
1.你必须在左括号的右侧和右括号的左侧各加一个空格,否则会报错。
2.test命令使用标准的数学比较符号来表示字符串的比较,而用文本符号来表示数值的比较。很多人会记反了。使用反了,shell可能得不到正确的结果。
#!/bin/bash str="this is text"; #使用变量 echo "这是一个测试文本"${str}; #使用一个命令的结果做操作 for var in $(cat /etc/passwd|cut -d ":" -f 1) do echo $var; done
if语句中用[]来判定,常用等式中用$(())来获取结果