目录
1 解析shell
shell是一个解释器,为了解释Unix命令,目的就是交互,因为shell就是为了实现Unix命令的思想来引入的;shell命令就是Unix系统命令;shell同时又是一种编程语言,如提供了变量定义、控制结构等。所以shell包含了unix系统命令、系统命令解释器和编程语言三个部分。 shell是一种泛称。Bash shell是shell的一种具体实现,它实现了定义了具体的UNIX系统命令、系统命令解析器和脚本编程语言。
2 注释
1 多行注释
1 2 3 4 |
if fase then //注释语句块 fi |
2 单行注释
1 |
# |
3 变量
3.1 变量
shell变量有四种:(1)本地变量、(2)环境变量,还有两种特殊变量:(3)位置变量和(4)特定变量参数。
3.2 变量操作
1. 使用常数赋值
1 2 3 |
# a和=之间没有空格。 a=3 b="hello" |
2. 使用变量赋值
1 2 3 |
# b前面没有$。变量作为左值是不加$,作为右值时才加上符号$ a=3 b=$a |
有时在$a两边最好加上双引号,但是这里会有问题,$a如果变量的值包含空格,例如hello world,那么该语句就会报错。
1 2 3 4 5 |
if [ "$a" = "abc" ];then echo "$a is abc" else echo "$a is not abc" fi |
3.变量作和
1 2 |
count=3 count=`expr $count + 3` |
注意:expr格式为
1 |
expr 空格 参数1 空格 操作符 空格 参数2 |
4 表达式
本小节主要介绍两个命令test和expr命令,正确返回0,错误返回1。如下
(1)test命令
- test命令写法 [ 空格 condition 空格]
- 三个逻辑操作符 -a 、-o、 !
- 对于字符串、数字、文件状态的判断条件
(2)expr实现变量类加
4.1 test命令
test可以测试文件状态、字符串和数字三个应用。
1. test逻辑操作符
(1)与 -a
(2)逻辑或 -o
1 |
[ "test"=="test" -o "hello"=="hello" ] |
(3)逻辑否 !
1 2 |
[ ! "test"=="test" ] echo $? |
结果为:1
2. test 两种写法
(1)写法1: test condition
(2)写法2:[空格 condition 空格]
3. 应用1:测试文件状态
(1)条件
(2)举例
1 2 3 4 |
test -f test.txt echo $? [ -f test.txt ] ehco $? |
4. 应用2:测试字符串
(1)条件
- == 两个字符串相等
- != 两个字符串不等
- -z 字符串为空串
- -n 非空字符串
4. 应用3:测试数字
(1)条件
- -eq 数值相等
- -ne 数值不相等
- -gt 第一个数大于第二个数 greater than
- -ge 第一个数大于等于第二个数
- -lt 第一个数小于第二个数 less than
- -le 第一个数小于等于第二个数
(2)举例
1 2 3 4 5 6 7 |
#变量和数值比较 number=3 [ $number -eq 3 ] echo $? #都是数值时 [echo 3 -eq 3] echo $? |
5. 应用4 测试布尔
1 2 3 4 5 |
mark=false if $mark then echo "错误信息" fi |
4.2 expr命令
1. expr介绍
expr命令一般作用于整数,一般格式为:expr argument 空格 operator 空格 argument
2. 使用
(1)直接使用
expr 3 空格+空格 3
输出结果为6
(2)和变量一起使用,实现变量累加
LOOP=1;
LOOP=expr $LOOP + 1
echo $LOOP
3. expr和test比较
二者都以0作为正确,1作为错误。
5 控制结构
5.1 if…then…fi
1. 写法
1 2 3 4 5 6 7 8 9 |
if 条件 then 操作1 elif 条件 then 操作2 else 操作3 fi |
5.2 for…do…done的四种方式
1 方式1: 字符串
(1)写法
1 2 3 4 |
for var in con1 con2 con3 do 程序段 done |
(2)举例
1 2 3 4 |
for var in "apple" "pie" do echo $var done |
执行结果为
apple
pie
2. 方式2 for loop in ls 路径
(1)写法
1 2 3 4 |
for loop in `ls 路径` do #对元素进行操作 done |
(2)举例
1 2 3 4 |
for var in `ls /home/hadoop/shelllearn` do echo $var done |
3. 方式3 for loop in ${数组[*]}
1 2 3 4 |
for loop in ${数组[*]} do #对元素进行操作 done |
4方式4: 数值
(1)写法
1 2 3 4 |
for ( ( 初始值; 限制值;执行步长) ) do 程序段 done |
(2)举例
1 2 3 4 5 6 7 |
#!/bin/sh echo "learn for..do...done" count=5 for ((i=1;i<=$count;i=i+1)) do echo $i done |
结果:
1 2 3 4 5 6 7 |
learn for ..do ...done 1 2 3 |
5.3 whie…do…done
1. 写法
1 2 3 4 |
while do //操作 done |
6 I/O标准输入输出
6.1 echo
1. -n 代表不自动换行
echo -n ”hello“
6.2 read
1. read 变量名
1 2 3 4 5 |
#!/bin/bash echo -n "Enter your name:" //参数-n的作用是不换行,echo默认是换行 read name //从键盘输入 echo "hello $name,welcome to my program" //显示信息 exit 0 //退出shell程序。 |
2. read -p “字符串” 变量名
7 读写文件
7.1 按行读取一个文件
使用cat 、while和read来完成。创建一个文件test,内容是
hadoop
lucene
machine learning
代码如下:
1 2 3 4 |
cat test|while read line do echo $line done |
结果显示:
hadoop
lucene
machine learning
7.2 读取每一个单词
使用cat和for实现,按空格切割。对于上述同一文件test,代码如下:
1 2 3 4 5 |
#!/bin/sh for line in `cat test` do echo $line done |
结果显示:
hadoop
lucene
machine learning
7.3 写入文件
1. echo “hello” > file.txt
这是将“hello”内容写入到file.txt中,首先删除文件内容,然后写入
2. ehoc “hello” >> file.txt
追加文件内容
8 函数
1. 函数解析
(1)函数定义写法
1 2 3 4 |
函数名 { } |
(2)在定义函数中使用形参
1 |
_temp1=$1和_temp=$2 |
(3)在使用函数时向函数传递形参
1 |
函数名 参数1 参数2 |
(4)返回值
1 |
$? |
2. 使用将其他文件中函数,使用格式为:
1 |
.空格<全路径> |
8.1 单个文件中函数解析
8.1.1 函数写法和使用函数
1. 函数写法
1 2 3 4 |
函数名() { } |
2. 使用函数
使用函数时,直接输入函数的名字,如下代码
1 2 3 4 5 6 7 8 |
#! /bin/sh # function hello() { echo "first function" } echo "hello()---" hello //直接调用函数的名字 |
8.1.2 向函数中传递参数
1. 在定义函数时,函数内重新设置中间变量保存所传的参数。设置的变量形式为“下划线+变量名”。直接对中间变量进行赋值,如_term=$1可以将第一个参数赋值给_term。使用如下:
- $0代表的是函数名字
- $1 ,$2,….代表的是第1个参数,第2个参数….
- $#代表的是函数参数的个数
2. 在使用函数时,没有如C/C++那样的函数列表,如果含有参数就在执行函数时,输入如下命令:
1 |
函数名 参数1 参数2 |
8.1.3 函数返回结果
通过$?来获取函数返回的结果。
8.2 函数位于其他文件
8.2.1 函数文件的导入
1. 使用写法
类似于C/C++中#include和python中模块导入import。这里写法如下
1 |
. 空格<全路径> |
2. 举例
创建一个function.sh,如下
1 2 3 4 5 |
#!/bin/sh test() { echo "hello function1" } |
定义一个userfunction.sh文件如下:
1 2 3 |
#!/bin/sh . /home/hadoop/shelllearn/function.sh test |
8.2.2 set命令
用于查看当前shell文件导入的函数有哪些导入函数。如下定义一个testset.sh文件,如下:
1 2 3 |
!/bin/sh . /home/hadoop/shelllearn/function.sh set |
8.2.3 撤销函数加载
1 |
unset 函数名 |
举例如下:
1 2 3 4 5 6 7 8 9 |
#!/bin/sh . /home/hadoop/shelllearn/function.sh test # 只执行此处的test函数 unset test test # 此处的test函数不能执行,它已经被unset撤销加载了 |
此时运行结果是:只执行一次test,第二个tes不执行。
9 脚本中运行Linux命令
有两种方法,如下
1方式1 使用反引号
1 |
content=`pwd` |
2方式2 $(命令语句)
1 |
content=$(pwd) |
10 脚本中接受参数
脚本形参使用和函数形参使用是一样的。
1. 在定义脚本中如下:
- $0代表的是函数名字
- $1 ,$2,….代表的是第1个参数,第2个参数….
- $#代表的是函数参数的个数
2.在使用脚本时如下
1 |
脚本名字 参数1 参数2 |
11 错误处理
1 从脚本中退出
1 |
exit 1 |
举例如下如下,执行如下脚本时,调用了一个jar包,当jar返回错误时,脚本就退出:
1 2 3 4 5 6 |
command="sh bin/import_daily_asset.sh -date=" $command$year$month$prefix$i if [ $? -eq 1 ] then exit 1 fi |
对应的java的main函数如下:
1 2 3 4 5 6 7 8 9 10 |
public static void main(String[] args) { try { ....... System.exit(0); } } catch (Exception e) { System.err.println(e.getMessage()); System.exit(1); } } |
12 数组
1. 数组定义
1 |
()#元素之间是空格 |
2. 数组前面都有一个${}
(1)对于求取数组的长度命令为:${#a[*]}
(2)访问一个元素${a[3]}
(3)打印一个数组${a[*]}
3. 数组的更新操作:插入、删除、更新
(1)插入
1 |
a[3]=9 |
(2)更新
1 |
a[3]=5 |
(3)删除
1 2 3 4 |
#删除一个元素 unset a[3] #删除一个数组 unset a |
12.1 数组写法
一对括号表示是数组,数组的元素用“空格”符号分割开。
1 |
a=(2 3 4 5 ) |
12.2 数组长度
1 |
${#a[*]} |
打印命令如下:
1 |
ehco ${#a[*]} |
或者给某个变量赋值
1 2 |
b=${#a[*]} echo $b |
12.3 数组读取
三种读取方式,如下
1. 直接打印数组
1 |
echo ${a[*]}; |
2. 访问数的某一个元素
1 |
echo ${a[2]} |
12.4 数组中元素的赋值、添加和删除元素
1. 数组元素的赋值
修改数组中某个元素的值
1 |
a[3]=10 |
此时数组的元素就变成了3。
1 2 3 |
i=3 a[$i]=10; echo ${a[3]} |
注意:有时数组及时数组的长度为3,此时也可以直接a[10]=6进行对数组赋值。只是从a[3]~a[6]的元素没有值。
2. 添加元素
1 |
a[4]=10 |
或者使用变量:
1 2 3 |
i=5 a[$i]=10; echo ${a[5]} |
3. 删除元素
(1)删除数组
1 |
unset a |
(2)删除某一个元素
1 |
unset a[1] |
12.5 数组切片和替换
1. 数组元素的切片
1 |
${数组名[@或*]:起始位置:长度} |
2. 举例如下
1 2 |
a=(0 1 2 3 4) echo ${a[*]:1:3} |
输出结果为:1 2 3
2. 数组特殊使用-数组元素的替换
1 |
${数组名[*]/查找字符/替换字符} |
但是该操作不会改变原数组的内容,如下
如果要改变数组中元素的值,如下命令:
12.6 数组之间复制
1. 写法
1 |
新数组=(${a[*]}) |
2. 举例
1 2 |
a=(1 2 3) list=(${a[*]}) |
12.7 数组的遍历
1. 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/sh a=(1 2 3) i=0 len=${#a[*]} echo $len while true do if [ $i -ge $len ] then break fi echo ${a[$i]} i=`expr $i + 1` done |
12.8 字符串和数组转换
1. 代码
1 2 3 4 5 6 |
#!/bin/bash a="one,two,thre" IFS="," //第一步 定义分割符 a=($a) //第二步 生成新的数组 echo ${a[*]} echo ${#a[*]} |
分为两步:
(1)第一步 IFS=”分隔符”
(2)第二步 数组=($字符串)
2. 注意
使用这个命令时一定要注意开头是
1 |
#! /bin/bash |
而不是
1 |
#! /bin/sh |
13 String处理
1 按指定的字符串截取:
(1)第一种方法:
- ${varible##*string} 从左向右截取最后一个string后的字符串
- ${varible#*string}从左向右截取第一个string后的字符串
- ${varible%%string*}从右向左截取最后一个string后的字符串
- ${varible%string*}从右向左截取第一个string后的字符串
其中“*”只是一个通配符可以不要,例子:
1 2 3 4 5 |
$ MYVAR=foodforthought.jpg $ echo ${MYVAR##*fo} rthought.jpg $ echo ${MYVAR#*fo} odforthought.jpg |
(2)第二种方法:${varible:n1:n2}:截取变量varible从n1到n2之间的字符串。
可以根据特定字符偏移和长度,使用另一种形式的变量扩展,来选择特定子字符串。试着在 bash 中输入以下行:
1 2 3 4 5 |
$ EXCLAIM=cowabunga $ echo ${EXCLAIM:0:3} cow $ echo ${EXCLAIM:3:7} abunga |
2. 通过sed命令来处理文本
参考:http://www.heartthinkdo.com/?p=210
14 Demo
14.1 拼接一个月每日日期生成一个执行命令
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#!/bin/sh #打印每一个月 year=2017 month=03 days=31 prefix=0 for ((i=1;i<=$days;i=i+1)) do command="sh bin/print.sh -date=" if(($i<10)) then echo $year$month$prefix$i $command$year$month$prefix$i else echo $year$month$i $command$year$month$i fi done |
在bin/print.sh为
1 2 3 |
#!/bin/bash echo "excute" $0 $1 |
14.2 检测服务脚本
检测服务是挂掉,如果挂掉,就重新启动
1 2 3 4 5 6 7 |
#!/bin/sh pid=$(ps -ef |grep appName | grep 'java -jar'| awk -F ' ' '{print $2}') if [ -z $pid ] then echo "app is killed,now to restart---" . /xxx/start.sh fi |
附1-expect脚本
如下是使用expect脚本进行scp文件的,脚本名称为scp-file.sh
1 2 3 4 5 6 7 8 9 10 |
#!/bin/bash # 1.filepath expect -c " spawn scp $1 user@ip:/home/user/path expect { \"*assword\" {set timeout 300; send \"passWord\r\";} \"yes/no\" {send \"yes\r\"; exp_continue;} } expect eof" |
在使用时,sh scp-file.sh /home/user/fille.txt
(全文完)