shell编程规范
脚本文件规范
1 文件的扩展名必须是.sh
2 文件的首行必须使用#! 指定脚本的shell运行环境(即脚本解释器)
如: #!/bin/bash
3 脚本中的行注释为 #
4 指令、选项、参数之间即使有多个空格仍会被视为一个空格
5 tab键形成的空白也被视为一个空格键
6 空白行会被忽略
实例:
#!/bin/bash
# 注释
echo "hello world"
脚本文件的执行
-
使用bash 程序来调用执行,主需要有读(r)权限即可
sh *.sh bash *.sh
-
直接执行脚本,需要有读执行权限(rx)
./*.sh chmod +x *.sh
-
借助变量PATH功能
将*.sh放入到~/bin目录下,因为PATH里拼接了~/bin目录 注意:~/bin目录必须自行创建
shell中变量的用法
1 变量的命名规范
- 命名只能使用英文字母。数字和下划线。首个字符不能是以数字开头
- 字母习惯用大写
- 中间不能有空格
- 不能使用标点符号
- 不能使用bash 里关键字
2 变量的使用规则
- 直接定义变量名称,没有类型需要强调(x=1,y=2,z=x+y)
- 赋值时,"="前后不能有空格
- 命令的执行结果赋值给变量时,使用反单引号 如 T=‘data’
- 调用变量时,必须使用$ 格式: $变量名 或者 ${变量名}
变量分类
- shell中变量分为三种:局部变量 环境变量 特殊变量
局部变量:用户自定义,在脚本中或者命令中定义
环境变量:保存和系统操作相关的数据,$HOME $PWD $SHELL $USER等
特殊变量:
位置参数:向脚本中传递参数或者数据,变量名不能自定义,变量作用固定。
预定义参数:是bash中已经定义好的变量,变量名,作用固定
-
局部变量 :用户自定义变量,由字母或者下划线开头,由字母数字或者下划线序列组成,大小写字母意义不同,变量名长度没有限制
- 变量调用时,要在变量名前面加 $
- 习惯使用大写字母命名 ,赋值时不能在=前后加空格 变量=值
1、定义时赋值:等号两侧不能有空格 A=33 2、将一个命令的执行结果赋值给变量 A=`ls -l` A=$(ls -l) 进行逻辑运算 $(()) A=$((1+2)) A=`expr 4 + 5 ` 3 将一个变量赋值给另一个变量 A=$STR
- 变量叠加
A=123 C="$A"456 D=${A}789 # 单引号里面的内容会全部输出,双引号会输出对应的值
- 列出所有变量: set
- 删除变量 unset A 撤销变量A 静态变量不能unset readonly B=5
- 作用域为当前的shell环境,仅在当前的shell实例中有效
-
环境变量: 系统设置好的,作用域: 当前shell以及所有子shell
-
声明变量 export 变量名=变量值
-
¥#常见配置文件如下:
-
/etc/profile 针对系统所有用户生效,此文件应用于所有用户
-
$HOME/.bash_profile 针对特定用户生效,
$HOME 为用户的宿主目录。每次用户登录系统后,首先继承/etc/profile文件中的定义在应用bash_profile文件中的定义
-
-
-
位置参数变量
$n n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,大于等于10的参数需要用大括号包含 ${10} $* 代表命令行中所有参数,把所有参数看成一个整体。以 “$1 $2 ... $n”的形式输出所有参数 $@ 代表命令行中所有参数,把每个参数区分对待,以“$1”“$2”...的形式输出所有参数 $# 参数个数 #!/bin/bash echo $1 echo $# echo $2 echo $* echo $@ 该方式可以接收命令行参数 ,传参 循环输出参数 #!/bin/bash echo "test \$*" for i in $* do echo $i done echo "test \$@" for i in $@ do echo $i done echo "test \"\$*\"" for i in "$*" do echo $i done echo "test \"\$@\"" for i in "$@" do echo $i done 输出: sh 2.sh 1 2 3 test $* 1 2 3 test $@ 1 2 3 test "$*" 1 2 3 test "$@" 1 2 3
-
预定义变量
$? 执行上一个命令的返回值,执行成功,返回0,执行失败 返回非0 $$ 当前进程号(PID) $! 后台运行的最后一个进程号,最近一个被放入当后台执行的进程 & vim pre.sh pwd > /dev/null echo $$ bash *.sh ; echo $?
read命令
- read [选项] 值
- read -p (提示语句) -n (字符个数) -t(等待时间,单位为秒) -s(隐藏输入)
read -t 30 -p "please input your name:" NAME
echo $NAME
read -s -p "please input your age:" AGE
echo $AGE
read -n 1 -p "please input your sex [M/F]:" GENDER
echo $GENDER
# 注意:
1、在输入时,如果输错了要删除执行ctrl+del
2、符号不要输入中文
3、NAME 与“之间要有空格
test测试命令
文件类型检测
test -e filename # 检测filename是否存在
test -d filename # 检测filename是不是目录
test -f filename # 检测filename是不是普通文件
test -L filename # 检测filename是不是软连接文件
文件属性检测
test -r filename # 检测文件是否有可读权限
test -w filename # 检测文件是否有可写权限
test -x filename # 检测文件是否有可执行权限
两个文件的比较
test file1 -nt file2 # 检测file1是否比file2新
test file1 -ot file2 # 检测file1是否比file2旧
test file1 -ef file2 # 检测file1与file2是否为同一文件
两个整数比较
test n1 -eq n2 # 检测n1 n2 是否相等
test n1 -ne n2 # 检测n1 n2 是否不等
...
条件控制
- if 条件语句-单分支
单分支if/else语句
if [ 条件判断式 ]
then
程序
fi
或者
if [条件判断式] ; then
程序
fi
eg:
#!/bin/bash
A=$1
if [ $A == "stop" ]
then
systemctl stop firewalld
fi
- elif多分支
#!/bin/bash
A=$1
if [ $A == "stop"]
then
systemctl stop firewalld
elif [ $A == "start" ]
then
systemctl start firewalld
else
systemctl status firewalld
fi
-
case : case 变量的值用来匹配value1 value2 等,
匹配到后则执行后面的命令
#!/bin/bash
CMD=$1
case $CMD in
start)
echo "starting"
;;
stop)
echo "stoping"
;;
test)
echo "testing"
;;
*)
echo "Usage: {start|stop}"
;;
esac
循环
- for循环
遍历:
#!/bin/bash
for N in 1 2 3
do
echo $N
done
for ((i=0;i<=5;i++))
do
echo "hi $i"
done
# 计算从1到100的和
#!/bin/bash
for ((i=0;i<=100;i++))
do
sum=(($sum+$i))
done
echo $sum
for ((i=0;i<=100;i++)); do mysum=$(($mysum+$i)); done ; echo $mysum
- while 循环
while [ expression ]
do
command
...
done
# 求1-10各个数的平方和
#!/bin/bash
num=1
while [ $num -le 10 ] #((i<=10))
do
sum=`expr $num \* $num` # sum1=$(($sum * $sum))
echo $sum
num=`expr $num + 1`
done
函数
先定义再调用,
格式:
函数名()
{
command1
command2
return 返回值变量
}
结构
[ function ] funname [()]
{
action;
[return int;]
}
eg:
#!/bin/bash
function start() {
echo "starting"
}
function stop {
echo "stop"
return 3
}
restart() {
echo "restarting"
}
$1; echo $?
注意:
如果函数名后面没有(),在函数名和{之间,必须要有空格
函数返回值,只能通过$?系统变量来获得,
没有return,将最后一条命令的运行结果作为返回值
return会转成数值 [0-255]
脚本调试
- 测试脚本
#!/bin/bash
a=$1
set -x #只对set -x 后面的代码进行调试
b=3
echo "b:"+$b
c=$a
echo $a
执行: bash -x test.sh # 显示该脚本所有变量的值
-n 不行脚本,只检测语法的模式,将返回所有语法错误,如:函数没有正确闭合
-v 执行并显示脚本内容
cut命令
cut [选项] 文件名 默认分割符是制表符,一个制表符代表一列
选项:
-f 列号: 提取第几列
-d 分隔符: 按照指定分割符分割列
cut -f 2 aa.txt 提取第二列
cut -d ":" -f 1,3 /etc/passwd 以:分割,提取第1列和第3列
cat /etc/passwd |grep /bin/bash |grep -v root |cut -d ":" -f 1 获取所有可以登录的普通用户用户名
cut的局限性 不能分割不定长度的空格
比如 :df -h 不能使用cut分割
awk介绍
文本分析工具,将文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分在进行分析处理
语法: awk '条件1{动作1}条件2{动作2}...'文件名
条件 (Pattern)
一般关系表达式作为条件: > >= <=等
动作(Action):
格式化输出
流程控制语句
eg df -h |awk '{print \$1 "\t" \$3}' 显示第一列和第三列
FS内置变量
cat /etc/passwd |grep "/bin/bash" |awk 'BEGIN {FS=":"}{print $1 "\t" $3}'
cat /etc/passwd |grep "/bin/bash" |awk -F : '{print $1 "\t" $3}'
BEGIN在所有数据读取之前执行
sed介绍
sed: stream editor
sed是一个非交互性文本编辑器,它编辑文件或标注输入导出的文本拷贝,标准输入可能来自键盘 文本重定向 字符串或者变量,或者是一个管道的文本
sed不与初始化文件打交道,操作一个拷贝,所有改动如果没有重定向到一个文件,将输出到屏幕
sed [选项]‘[动作]’ 文件名
-n 使用安静模式,显示经过sed处理过的数据
-e 允许多点编辑
-i 直接修改读取的档案内容,不由屏幕输出
a 新增
c 替换
d 删除
i 插入
p 打印
s 查找并替换 eg 1,20s/old/new/g # 1,20 第一到20行,s/开头 /g结尾 将old换成new
sed '2p' sed.txt 显示第二行和所有数据
sed -n '2p' sed.txt 只显示第二行
sed -n '2,3p' sed.txt
df -h |sed -n '1p' 接收命令结果数据