linux shell编程
Posted 野生java研究僧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux shell编程相关的知识,希望对你有一定的参考价值。
linux shell编程
- 1.shell脚本概述
- 2.脚本的调用形式
- 3.shell脚本语法
- 4.变量
- 5.预设变量
- 6.if控制语句
- 7.算术运算
- 8.Shell case...esac 语句
- 9. 循环
- 10.函数
- 11.shell脚本错误时直接退出
- 12.shell定时任务
1.shell脚本概述
hell 是一种脚本语言
脚本:本质是一个文件,文件里面存放的是 特定格式的指令,系统可以使用脚本解析器 翻译或解析 指令 并执行(它不需要编译)
shell 既是应用程序 又是一种脚本语言(应用程序 解析 脚本语言)
shell命令解析器:
系统提供 shell命令解析器: sh ash bash
查看自己linux系统的默认解析:echo $SHELL
2.脚本的调用形式
打开终端时系统自动调用:/etc/profile 或 ~/.bashrc
/etc/profile
此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行,系统的公共环境变量在这里设置
开机自启动的程序,一般也在这里设置
~/.bashrc
用户自己的家目录中的.bashrc
登录时会自动调用,打开任意终端时也会自动调用
这个文件一般设置与个人用户有关的环境变量,如交叉编译器的路径等等
用户手动调用:用户实现的脚本
3.shell脚本语法
3.1 脚本开头标识
定义以开头:#!/bin/bash ,#!用来声明脚本由什么shell解释,否则使用默认shell , shell脚本文件名默认设置为 sh,用于标识这是一个脚本
#!/bin/bash
3.2 脚本注释
单个"#"号代表注释当前行
3.3 给脚本加上可执行权限
chmod 774 shell.sh
3.4 shell脚本的运行方式
三种执行方式 (./xxx.sh bash xxx.sh . xxx.sh)
三种执行方式的不同点(./xxx.sh bash xxx.sh . xxx.sh)
./xxx.sh :先按照 文件中#!指定的解析器解析
如果#!指定指定的解析器不存在 才会使用系统默认的解析器
bash xxx.sh:指明先用bash解析器解析
如果bash不存在 才会使用默认解析器
. xxx.sh 直接使用默认解析器解析(不会执行第一行的#!指定的解析器)但是第一行还是要写的
三种执行情况:
打开终端就会有以后个解释器,我们称为当前解释器
我们指定解析器的时候(使用 ./xxx.sh 或 bash xxx.sh)时会创建一个子shell解析 脚本
3.5 检测脚本是否正确
bash -n shellName.sh (不在当前目录下加绝对路径) 检查语法错误
bash -x shellName.sh (不在当前目录下加绝对路径) 检查逻辑错误
3.6 重定向的使用
类型 | 操作符 | 用途 |
---|---|---|
重定向输入 | < | 从指定文件读取数据 |
重定向输出 | > | 将标准输出结果保存到指定的文件,并且覆盖原有文件 |
>> | 将标准输出追加到指定的文件的尾部,不覆盖原有内容 | |
标准错误输出 | 2> | 将错误信息保存到指定文件,并且覆盖原有文件 |
2>> | 将错误信息追加到指定文件的尾部,不覆盖原有内容 | |
混合输出 | &>和2>&1 | 将标准输出,标准错误保存到同—文件中 |
3.7 获取上一条命令的执行结果
$?
案例:
#!/bin/bash
test "hello"
echo $? # $?= 0
test -z "admin"
echo $? # $?=1
4.变量
4.1 变量的定义和使用
定义变量: 变量名=变量值
如:num=20
引用变量: $变量名
unset :清除变量值
只读变量: readonly 变量名=变量值
4.2 从键盘上读取变量:
Read可以带有-a, -d, -e, -n, -p, -r, -t, 和 -s八个选项。
-d :表示delimiter,即定界符,一般情况下是以IFS为参数的间隔,但是通过-d,我们可以定义一直读到出现执行的字符位置。例如read –d madfds value,读到有m的字符的时候就不在继续向后读,例如输入为 hello m,有效值为“hello”,请注意m前面的空格等会被删除。这种方式可以输入多个字符串,例如定义“.”作为结符号等等。
-e :只用于互相交互的脚本,它将readline用于收集输入行。读到这几句话不太明白什么意思,先跳过。
-n :用于限定最多可以有多少字符可以作为有效读入。例如echo –n 4 value1 value2,如果我们试图输入12 34,则只有前面有效的12 3,作为输入,实际上在你输入第4个字符‘3’后,就自动结束输入。这里结果是value为12,value2为3。
-p :用于给出提示符,在前面的例子中我们使用了echo –n “…“来给出提示符,可以使用read –p ‘… my promt?’value的方式只需一个语句来表示。
-r :在参数输入中,我们可以使用’/’表示没有输入完,换行继续输入,如果我们需要行最后的’/’作为有效的字符,可以通过-r来进行。此外在输入字符中,我们希望/n这类特殊字符生效,也应采用-r选项。
-s :对于一些特殊的符号,例如箭头号,不将他们在terminal上打印,例如read –s key,我们按光标,在回车之后,如果我们要求显示,即echo,光标向上,如果不使用-s,在输入的时候,输入处显示^[[A,即在terminal上 打印,之后如果要求echo,光标会上移。
-t :用于表示等待输入的时间,单位为秒,等待时间超过,将继续执行后面的脚本,注意不作为null输入,参数将保留原有的值
read -p "请输入number的值" number
echo "$number"
4.3 读取多个变量的值:
#!/bin/bash
read height width
echo "height=$height"
echo "width=$width"
4.4 查看环境变量:
env
导出为环境变量:让其他shell脚本识别该变量,设为全局变量
source 脚本文件
source命令用法:
source FileName
作用:在当前bash环境下读取并执行FileName中的命令。
注:该命令通常用命令“.”来替代。
如:source .bash_rc 与 . .bash_rc 是等效的。
注意:source命令与shell scripts的区别是,
source在当前bash环境下执行命令,而scripts是启动一个子shell来执行命令。这样如果把设置环境变量(或alias等等)的命令写进scripts中,就只会影响子shell,无法改变当前的BASH,所以通过文件(命令列)设置环境变量时,要用source 命令。
4.5 注意事项
- 变量名只能包含英文字母下划线,不能以数字开头
- 1_num=10 错误
- num_1=20 正确
- 等号两边不能直接接空格符,若变量中本身就包含了空格,则整个字符串都要用双引号、或单引号括起来
- 双引号 单引号的区别
- 双引号:可以解析变量的值
- 单引号:不能解析变量的值
如果想在PATH变量中 追加一个路径写法如下:(重要!!!!)
export PATH=$PATH:/需要添加的路径
4.6 判断变量是否存在
$变量名:变量值 如果变量名存在,则为该变量名的值,否则为变量值
案例: 这种方式判断只支持数字 包含小数
echo $val:100
4.7 字符串操作
1.测量字符串长度
使用方式: $#字符串或字符串变量
str='admin'
echo $#str # 输出5
2.字符串截取
1.从指定位置一直截取到末尾 索引从0开始
使用方式: $字符串变量去掉$符号:截取的索引
例如:
#!/bin/bash
str='admin'
echo $str:2 # 最终输出 min
2.从指定位置截取n位字符
使用方式: $字符串变量去掉$符号:截取的索引:截取的长度
例如:
#!/bin/bash
str='admin'
echo $str:2:2 # 最终输出 mi
3.字符串替换 用新的字符串替换遇到的第一个旧字符串
使用方式:$原始字符串/需要替换的字符串/待替换的新字符串
#!/bin/bash
str='hello admin'
echo $str/"admin"/"root" # 最终输出 hello admin
4.字符串替换 用新的字符串替换遇到的蓑鲉旧字符串
使用方式:$原始字符串//需要替换的字符串/待替换的新字符串
#!/bin/bash
str='hello admin,hou are you admin'
echo $str//"admin"/"root" # 最终输出 hello admin
5.使用# 至左向右截取
案例:
#!/bin/bash
str='http://baidu.com/index.htm'
echo $str#*// # 输出 /baidu.com/index.htm 删除遇到的#*的字符,并且从左到右截取到最后
6.##号截取(自左向右)
案例:
#!/bin/bash
str='http://baidu.com/index.htm'
echo $str##*/ 输出: index.html # ##*/ 表示从左边开始,删除##*后匹配的最后一个字符及其后面的字符
7.%号截取(自右向左)
案例:
#!/bin/bash
str='http://baidu.com/index.htm' # 输出 http://baidu.com 删除 %匹配的字符以及匹配字符串后面的字符
echo $str%/*
8.%%号截取(自右向左)
#!/bin/bash
str='http://baidu.com/index.htm'
echo $str%%/* # 输出:http: 删除第一个匹配的字符及右边的所有字符
4.8 数组
我们可以用一个单一的阵列来存储所有上述提及的名称。以下是最简单的方法创建一个数组变量分配一个值,其索引之一。
# 1. 数组的初始化
#!/bin/bash
array=("value1" "value2")
echo $array[*]
# 2. 数组的赋值
array_name[index]=value
# 3. 数组的取值
array_name[index]
# 4. 特殊取值
array_name[*] # 取整个数组的全部value
array_name[@] # 取整个数组的全部value
array_name[0] # 获取数组的第一个元素
array_name[-1] # 获取数组的最后一个元素
# 5.获取数组的长度
#方式1: $#array[*]
#方式2: $#array[@]
# 6.删除数组和删除数组元素
unset array_name[index] #删除索引数组的第三个元素
unset array_name[key] #删除关联数组中索引为key的元素
unset array_name #删除数组
# 7.遍历数组
# 直接取值
for i in "$array_name[@]"
do
echo $i
done
#C语言风格遍历
for((i=0;i<$#array_name[@];i++))
do
echo $array_name[i]
done
# 8.字符串以冒号分隔存入数组
string="12:34:56"
array=($string/:/ )
# 9.$*和$@的区别
# 1. 当直接通过echo获取数组所有元素时,它们是一样的效果
# 2. $array_name[*]会将数组元素视为一个整体
# 3. $array_name[*]会将数组元素拆分为单独的个体
# 10.打印数组的下标值
echo $!array_name[@]
array_name 是数组名,索引是在阵列中,你要设置的项目索引,值是你想要的值设置该项目。
5.预设变量
预定义变量即Shell已经定义的变量,用户可根据Shell的定义直接使用这些变量,无需自己定义。所有预定义的变量都由$符和其他符号组成,常用的预定义变量如下所示。
(1)$#:表示命令行参数的个数。
(2)$@:包含所有的命令行参数,即“$1、$2、$3......”。
(3)$?:前一个命令的退出状态,正常退出返回0,反之为非0值。
(4)$*:包含所有的命令行参数,即“$1、$2、$3......”。
(5)$$:正在执行的进程的ID号。
脚本标量的特殊用法:
""[双引号:里面包含的变量会被解释]
''[单引号:包含的变量会当做字符串接收]
``[反引号:反引号的内容作为系统命令进行执行]
转义字符[\\t,\\n,\\r等..和c语言的一致]
6.if控制语句
6.0 shell 运算符
( ) | Change precedence |
---|---|
~ | 1’s complement |
! | Logical negation |
* | Multiply |
/ | Divide |
% | Modulo |
+ | Add |
- | Subtract |
<< | Left shift |
>> | Right shift |
== | String comparison for equality |
!= | String comparison for non equality |
=~ | Pattern matching |
& | Bitwise “and” |
^ | Bitwise “exclusive or” |
| | Bitwise “inclusive or” |
&& | Logical “and” |
|| | Logical “or” |
++ | Increment |
– | Decrement |
= | Assignment |
*= | Multiply left side by right side and update left side |
/= | Divide left side by right side and update left side |
+= | Add left side to right side and update left side |
-= | Subtract left side from right side and update left side |
^= | “Exclusive or” left side to right side and update left side |
%= | Divide left by right side and update left side with remainder |
6.1 Shell if…fi语句
if [ expression ]
then
Statement(s) to be executed if expression is true
fi
案例:
#!/bin/bash
# 当if条件成立的时候,then 到 fi 之间的语句才会被执行
if [ 1 = 1 ]
then
echo "条件成立"
fi
6.2 Shell 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
案例:
#!/bin/bash
# 当if条件成立的时候,then 到 fi 之间的语句才会被执行,当条件不成立的时候执行 else 到 if 之间的语句
if [ 1 == 2 ]
then
echo "条件成立"
else
echo "条件不成立"
fi
6.3 Shell if…elif…fi 语句
语法:
if [ expression 1 ]
then
echo " Statement(s) to be executed if expression 1 is true"
elif [ expression 2 ]
then
echo "Statement(s) to be executed if expression 2 is true"
elif [ expression 3 ]
then
echo "Statement(s) to be executed if expression 3 is true"
else
echo "Statement(s) to be executed if no expression is true"
fi
案例:
#!/bin/bash
number=$1
if [ $number == 10 ]
then
echo " Statement(s) to be executed if expression 1 is true"
elif [ $number -gt 10 ]
then
echo "Statement(s) to be executed if expression 2 is true"
elif [ $number -lt 10 ]
then
echo "Statement(s) to be executed if expression 3 is true"
else
echo "Statement(s) to be executed if no expression is true"
fi
6.4 判断某个字符串中是否出现指定字串
#!/bin/bash
str='http://baidu.com/index.htm'
target="baidu"
if [[ $str =~ $target ]]
then
echo "包含"
else
echo "不包含"
fi
6.5 文件测试
-f : 判断文件是否为普通文件
-d :判断是否目录
-b :判断是都块设备文件
-c :判断是都字符设备文件
-S :判断是否socket文件
-p: 判断是否管道文件
-h: 判断是都为符号链接
-L: 文件存在且有符号链接
文件大小存在性:
-e : 判断文件或者目录是否存在
-s : 文件或者或者目录存在且大小大于0
文件读写特性
-r: 判断文件是否有可读权限
-w:判断文件是否具有可写权限
-x: 判断文件是否具有可执行的权限
-g:判断文件是否具有sgid位
-u:判断文件是否有suid位
-k:判断是否设置了粘滞位,文件设置粘滞位后会被写入缓存
文件修改时间:
file1 -nt file2 : 判断file1是否 比file2 新
file1 -ot file2 : 判断file1是否 比file2 旧
这里就不一个一个举例 写一个demo即可
#!/bin/bash
if [ -f $1 ]
then
echo "$1 是文件"
else
echo "$1 是目录"
fi
6.6 数值测试
含义 | 英文单词 | shell比较符 |
---|---|---|
相等 | equal | -eq |
不相等 | not equal | -ne |
大于 | greater than | -gt |
大于等于 | greater equal | -ge |
小于等于 | less equal | -le |
小于 | less than | -lt |
案例:猜数字游戏
#!/bin/bash
number=$1
if [ $number -gt 50 ]
then
echo "猜大了"
elif [ $number -lt 50 ]
then
echo "猜小了"
else
echo "恭喜你猜到了,幸运数字就是: 50"
fi
6.7 条件测试
命令执行控制:
command1 && command2 左边的命令执行成功才执行右边的命令
command1 || command2 左边的命令执不成功才执行右边的命令
案例:
test 1 == 1 && echo "ture"
test 1 == 2 || echo "ture"
6.8 多重条件判定
判定符 | 解释 |
---|---|
-a | 两个条件同时成立 |
-o | 只需要一个条件成即可 |
! | 取反,如果条件true,就返回false |
案例:
test 1==1 -a 2 == 2 && echo "true"
test ! [ 1==3 -a 2 == 2 ] && echo "true"
6.9 字符串测试
语法:
test expression
[ expression ]
运算符 | 说明 |
---|---|
string | 判断指定的字符串是否为空,不为空返回0 |
string1 = string2 | 判断两个字符串是否相等,相等返回0 |
string1 != string2 | 判断两个字符串是否不相等,不相等返回0 |
-n string | 判断string是否为非空串,非空返回0 |
-z string | 判断string是否为空串,空串返回0 |
7.算术运算
7.1 使用let命令
使用let命令可以执行一个或者多个算术表达式,其中的变量名无需使用$符号。如果表达式中含有空格或者其他特殊字符,需要引用起
#!/bin/bash
n=15
let n=n+1
echo "$n"
7.2 expr命令
在使用运算符时,需要对运算符进行转义,如果有括号,也需要对括号进行转义。不能使用紧凑格式,要使用松散格式,举例:
#!/bin/bash
result=`expr 2 + 100`
echo "$result"
7.3 $[expression]
#!/bin/bash
#采用紧凑格式
result=$[3+7]
echo "$result"
#采用松散格式
result=$[ 3 - 7 ]
echo "$result"
7.4 使用$((expression))
使用这种形式进行算术运算写法比较自由,无需对运算符和括号做转义处理,可以采用松散或者紧凑的格式来书写表达式。
#!/bin/bash
#采用紧凑格式
result=$((3+7))
echo "$result"
#采用松散格式
result=$(( 3 - 7 ))
echo "$result"
7.5 数字常量的进制
数字常量的进制
默认情况下,Shell总是以十进制来表示数字。但是用户也可以在Shell中使用其他进制来表示数字,比如二进制,八进制,十六进制。在Shell中,用户可以使用两种语法来表示不同的进制
1.增加前缀:0开头的数字表示0进制,0x开头的数字表示十六进制
2.使用#号:2#1001表示二进制,8#20表示八进制
案例:
#!/bin/bash
a=$((2#1000))
((b=8#20))
((c=16#10))
d=$[0x10]
e=$[020]
f=20
((g=0x10))
((h=(1+3)*5))
echo "$a $b $c $d $e $f $g $h"
8.Shell case…esac 语句
可以使用多个if…elif 语句执行多分支。然而,这并不总是最佳的解决方案,尤其是当所有的分支依赖于一个单一的变量的值。
Shell支持 case…esac 语句处理正是这种情况下,它这样做比 if…elif 语句更有效。
case…esac 语句基本语法 是为了给一个表达式计算和几种不同的语句来执行基于表达式的值。
解释器检查每一种情况下对表达式的值,直到找到一个匹配。如果没有匹配,默认情况下会被使用。
case word in
pattern1)
Statement(s) to be executed if pattern1 matches
;;
pattern2)
Statement(s) to be executed if pattern2 matches
;;
pattern3)
Statement(s) to be executed if pattern3 matches
;;
esac
这里的字符串字每个模式进行比较,直到找到一个匹配。执行语句匹配模式。如果没有找到匹配,声明退出的情况下不执行任何动作。
没有最大数量的模式,但最小是一个。
当语句部分执行,命令;; 表明程序流程跳转到结束整个 case 语句。和C编程语言的 break 类似。
案例:输入数字 1-7 输出对应的星期几?
#!/bin/bash
key=$1
case "$key" in
"1") echo "星期一"
;;
"2") echo "星期二"
;;
"3") echo "星期三"
;;
"4") echo "星期四"
;;
"5") echo "星期五"
;;
"6") echo "星期六"
;;
"7") echo "周日"
;;
esac
9. 循环
9.1 while循环
while command
do
Statement(s) to be executed if command is true
done
里Shell命令进行计算。如果结果值是 true,给定语句被执行。如果命令为 false,那么没有语句将不执行,程序将跳转到done语句后的下一行。
案例:打印 1-10
#!/bin/bash
number=$1
while [ $number -lt 10 ]
do
let number=number+1
echo "number=$number"
done
执行: ./demo.sh 0
9.2 Shell for循环
循环操作项目清单。重复一组命令列表中的每个项目。
语法:
for var in word1 word2 ... wordN
do
Statement(s) to be executed for every word.
done
var是一个变量,word1 到 wordN 是由空格分隔的字符(字)序列的名称。每次for 循环的执行,变量var的值被设置为下一个单词的列表中的字,word1 到 wordN 。
案例:
#!bin/bash
read -p "input dir path" dir
for item in `ls $dir`;
do
echo $item
done
遍历某个文件夹下的所有文件和目录
#!/bin/bash
function getdir()
for file in $1/*
do
if test -f $file
then
echo $file
arr=($arr[*] $file)
else
getdir $file
fi
done
getdir $1
# 调用方式: ./demo.sh /web/jenkins/dir
9.3 循环中的break 和 continue
- break 语句 : 用于跳出循环
- continue 语句 : 跳过当前本次循环,继续下一次循环
9.4 until循环
until和while循环相反,until是当条件为假的时候就执行循环,一旦条件满足就退出循环
until condition
do
当 until 后面的条件不成立的时候,这里写需要做的事情
done
10.函数
函数允许您对分解成更小的,逻辑子部分,然后可以被要求执行各项任务时,它需要一个脚本的整体功能。
使用函数来执行重复性的任务,是一个很好的方式来创建代码的重用。代码重用是现代面向对象编程的原则的重要组成部分。
Shell函数是类似于其他编程语言中的子程序,过程和函数。
10.1 声明函数:
function_name ()
list of commands
声明一个简单的函数:
#!/bin/bash
hello()
echo "hello world"
# 调用hello函数
hello
10.2 传递参数给函数:
你可以定义一个函数,它接受参数,而调用这些函数。将这些参数代表$1,$2,依此类推。
案例: 输入两个数字,计算他们的和
#!/bin/bash
add()
let sum=$1+$2
echo $sum
# 函数外的$1 和 $2 有脚本参数传递,函数内的参数由 add后面的$1 和 $2 传递
add $1 $2
10.3 函数的返回值
如果你执行一个exit命令从一个函数内部,其效果不仅是终止执行的功能,而且Shell 程序中调用该函数。
如果你不是想,只是终止执行该函数,再有就是退出来的一个定义的函数。
根据实际情况,你可以从你的函数返回任何值,使用返回的命令,其语法如下
return code;
案例: 输入两个数,计算他们的乘积
#!/bin/bash
hello ()
echo "hello args: $1 $2"
let result=以上是关于linux shell编程的主要内容,如果未能解决你的问题,请参考以下文章