shell编程

php和java主要实现功能
shell简化管理操作

shell 基础

查看当前使用的shell:echo $SHELL
查看支持的shell: cat /etc/shells

#!/bin/bash声明使用bash开头,若当前使用其它shell时,执行这个脚本时,也会自动使用bash

赋予执行权限 chmod +x hello.shchmod 755 hello.sh
执行: ./hello.sh 或调用bash来执行 bash hello.sh

Bash变量

变量命名规则

  • 变量名必须以字母或下划线开头,名字中间只能由字母、数字和下划线组成
  • 变量名的长度不得超过255个字符
  • 变量名在有效范围内必须是唯一的
  • 在Bash中,变量的默认类型都是字符串型

用户自定义变量

变量名=变量值

注意:=两边不能有空格,变量值,可以用引号包起来,也可以不需要,但当变量值中含有空格时,一定需要引起来

变量的调用:在变量名前加$
echo $name

变量叠加

x=123
x="$x"456
x=${x}456
echo $x

# 注意,不能直接使用+,这会将加号直接当成字符串拼接在一起  

变量查看
env # 查看环境变量
set # 查看当前所有的变量,包括用户自定义变量与环境变量
set -u # 如果设置此选项,调用未声明变量时会报错(默认无任何提示)

变量删除unset 变量名(不需要加$)

环境变量

环境变量最好都设置为大写
对系统生效的环境变量名和变量作用是固定的

设置环境变量

export 变量名=变量值  
# 或
变量名=变量值
export 变量名

删除与查看与用户自定义变量一样

常用环境变量

  • HOSTNAME: 主机名
  • SHELL: 当前的shell
  • TERM: 终端环境
  • HISTSIZE: 历史命令条数
  • SSH_CLIENT: 当前操作系统环境是用ssh连接的,这里记录客户端IP
  • SSH_TTY: ssh连接的终端pts/1
  • USER: 当前登录的用户

PATH环境变量:系统查找命令的路径,冒号分隔
echo $PATH # 查看PATH环境变量
PATH="$PATH":/root/sh # 增加PATH变量的值

PS1环境变量: 命令提示符设置echo $PS1

  • d: 显示日期,格式为“星期 月 日”
  • H: 显示完整的主机名。如默认主机名“localhost.localdomin”
  • : 显示24小时制时间,格式为“HH:MM:SS”
  • A: 显示24小时制时间,格式为“HH:MM”
  • u: 显示当前用户名
  • w: 显示当前所在目录的完整名称
  • W: 显示当前所在目录的最后一个目录名
  • $: 提示符。如果是root用户会显示提示符为#,普通用户为$

语系变量
locale # 查询当前系统语系
LANG: 定义系统主语系的变量
LC_ALL: 定义整体语系的变量

echo $LANG # 查看系统当前语系
locale -a | more # 查看Linux支持的所有语系

位置参数变量

位置参数变量 作用
$n n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含,如${10}
$* 这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体
$@ 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待
$# 这个变量代表命令行中所有参数的个数
# !/bin/bash

# 注意需要使用双引号括起来,否则,其含义发生变化
for i in "$*"
do
    # 只循环一次
    echo "the parameters is: $i"
done


# 注意需要使用双引号括起来,否则,其含义发生变化
for i in "$@"
do
    echo "parameter: $i"
done

预定义变量

预定义变量 作用
$? 最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。
$$ 当前进程的进程号(PID)
$! 台后运行的最后一个进程的进程号(PID)

read: 接收键盘输入
read [选项] 变量名
-p: 在等待read输入时,输出提示信息
-t: 秒数,read命令会一直等待用户输入,使用此选项可以指定等待时间
-n:字符数,read命令只接受指定的字符数,就会执行
-s:隐藏输入的数据,适用于机密信息的输入

read -p "please input your passwd: " -t 30 -n 6 -s passwd

shell运算符

declare 命令

declare声明变量类型

declare [+/-][选项] 变量名
-: 给变量设定类型属性
+: 取消变量的类型属性
-a: 将变量声明为数组型
-i: 声明为整数型
-x: 声明为环境变量
-r: 声明为只读变量
-p: 显示指定变量的被声明类型

# 声明整数型  
a=1
b=2
declare -i c=$a+$b # 注意=号与+号两边都不能有空格
echo $c

# 声明数组变量
movie[0]=zp
movie[1]=tp
declare -a movie[2]=live

# 查看数组
echo ${movie}
echo ${movie[2]}
echo ${movie[*]}

# 声明环境变量
declare -x test=123 # 和export作用相似,但其实是declare命令的作用
declare -p # 列出系统中所有变量的类型

# 声明为只读属性,一般不要使用
declare -rx test=123 # 给ro赋予只读属性,但是注意只读属性会让变量不能修改,不能删除,甚至不能取消只读属性
declare +r test # 会报错,不能取消只读属性

# 查询变量的属性
declare -p # 查询所有变量的属性 
declare -p 变量名 # 查询指定变量的属性

数值运算的方法

方法1: 声明变量类型

# 声明整数型  
a=1
b=2
declare -i c=$a+$b # 注意=号与+号两边都不能有空格
echo $c

方法2: expr或let数值运算工具

a=1
b=2
d=$(expr $a + $b) # 注意+号两侧必须有空格
echo $d

方法3: $(( 运算式 ))$[运算式]

a=1
b=2
f=$((a+b)) # +号两侧有没有空格都可以
echo $f

推荐使用$((运算式))

运算符

优先级 运算符 说明
13 -+ 单目负、单目正
12 !, ~ 逻辑非,按位取反或补码
11 *, /, % 乘、除、取模
10 +, - 加、减
9 <<, >> 按位左移、按位右移
8 <=, >=, <, > 小于或等于、大于或等于、小于、大于
7 ==, != 等于、不等于
6 & 按位与
5 ^ 按位异或
4 | 按位或
3 && 逻辑与
2 || 逻辑或
1 =, +=, -=, *=, /=, %=, &=, ^=, |=, <<=, >>= 赋值、运算且赋值

变量测试

一般情况不需要使用
在脚本优化时才使用

环境变量配置文件

修改配置文件后,必须注销重新登录才能生效,使用source命令可以不用重新登录
source 配置文件. 配置文件

环境变量配置文件简介

常用配置文件

  • /etc/profile
  • /etc/profile.d/*.sh
  • ~/.bash_profile 只对当前用户有效
  • ~/.bashrc 只对当前用户有效
  • /etc/bashrc

环境变量配置文件的功能

配置文件加载顺序

正常登录,配置文件加载顺序:
/etc/profile --> /etc/profile.d/*.sh --> /etc/profile.d/lang.sh --> /etc/locale.conf~/.i18n
/etc/profile --> ~/.bash_profile --> ~/.bashrc --> /etc/bashrc --> 命令提示符

使用su命令切换用户,不是完整登录
/etc/bashrc --> /etc/profile.d/*.sh --> /etc/profile.d/lang.sh --> /etc/locale.conf~/.i18n

/etc/profile

主要是针对登录做配置

  • USER变量
  • LOGNAME变量
  • MAIL变量
  • PATH变量
  • HOSTNAME变量
  • HISTSIZE变量
  • umask: 查看系统默认权限(创建文件时的默认权限)
  • 调用/etc/profile.d/*.sh文件

umask权限: 四位,第一位为系统特殊权限,后三位为默认权限

  1. 文件最高权限为666,x权限必须由管理员授权
  2. 目录最高权限为777
  3. 权限不能使用数字进行换算,而必须使用字母
    文件最高权限: 666: rw-rw-rw-
    umask值: 022: ----w--w-
    最终创建文件权限: rw-r--r--
  4. umask 定义的权限,是系统默认权限中准备丢弃的权限

~/.bash_profile

加载~/.bashrc
将家目录下bin目录添加到环境变量
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH

~/.bashrc

自定义别名
加载/etc/bashrc

/etc/bashrc

  • PS1变量
  • umask
  • PATH变量
  • 未登录shell,则调用/etc/profile.d/*.sh文件

其他配置文件

~/.bash_logout 注销时生效的环境变量配置文件
如添加 history -c,退出后清除历史命令

~/.bash_history 历史命令保存文件
正确登出后,会将本次登录使用的命令,保存到这个文件

/etc/issue 本地终端警告信息,远程登录不起作用

转义符 作用
d 显示当前系统日期
s 显示操作系统名称
l 显示登录的终端号,这个比较常用
m 显示硬件体系结构,如i386、i686等
显示主机名
o 显示域名
显示内核版本
显示当前系统时间
u 显示当前登录用户的序列号

/etc/issue.net 远程终端警告信息
转义符在/etc/issue.net中不能使用
是否显示此信息,由ssh的配置文件/etc/ssh/sshd_config决定,加入Banner /etc/issue.net行才能显示(需要重启SSH服务service sshd restart)

/etc/motd 登录后欢迎信息
不管是本地登录,还是远程登录,都可以显示此信息

正则表达式

grep、awk、sed等命令可以支持正则表达式
ls、find、cp不支持正则,只能使用shell自已的通配符

通配符有*?[]

正则: http://www.cnblogs.com/chencye/category/839826.html

字符处理

字符截取命令

cut

cut [选项] 文件 列提取
-f: 列号,提取第几列,若取多列,则列号以英文逗号间隔
-d: 分隔符(默认为制表符),按照指定分隔符分割列,必须是单个字符

# 获取/bin/bash的所有普通用户名  
grep "/bin/bash" /etc/passwd | grep -v "root" | cut -f 1 -d ":"

# cut默认使用制表符分割,所以下面这条命令,不能分隔  
df -h | cut -f 5

# cut只会按照-d指定的串,进行分割,如下面命令,只以一个空格进行分割,所以只会取到第一列 (使用awk)
df -h | cut -f 1,3 -d " "

awk

测试test.txt

[chencye@centos7 empty]$ cat test.txt 
ID      name
1       a
2       b
3       c

printf
printf '输出类型输出格式' 输出内容
输出类型:
%ns: 输出字符串。n是数字,指代输出几个字符
%ni: 输出整数。n是数字,指代输出几个数字
%m.nf: 输出浮点数。m和n是数字,指代输出的整数位数和小数位数
输出格式:
a: 输出警告声音
: 输出退格键
f: 清除屏幕
: 换行
: 回车
: 水平输出退格键
v: 垂直输出退格键

printf '%s' $(cat test.txt) 不调整输出格式
printf '%s %s ' $(cat test.txt) 将输出与前面显示格式一样

print在每个输出后自动加入一个换行符(linux默认没有print命令),printf标准格式输出命令

awk
命令: awk '条件1 {动作1} 条件2 {动作2}...' 文件名

awk '{printf $1 " " $2 " "}' test.txt 没有条件,所有都输出
df -h | grep "/dev$" | awk '{print $5}' | cut -f 1 -d "%" 查看磁盘已使用百分比

BEGIN 在所有动作执行之前,先执行这个动作

cat /etc/passwd | awk 'BEGIN{FS=":"}{print $1 " " $3}' FS设置分隔符,如果没有BEGIN,将不起作用

END 在所有动作执行之后,最后再执行这个动作

条件: 运算符

cat test.txt | grep -v "name" | awk '$1==1 {print $2 "的ID是1"} $1==3 {print $2 "的ID是2"}'

字符增删改查命令

sed 轻量级流编辑器
主要用来将数据进行选取、替换、删除、新增的命令

sed [选项] '[动作]' 文件名

选项:
-n 一般sed命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕
-e 允许对输入数据应用多条sed命令编辑
-i 用sed的修改结果直接修改读取数据文件,而不是由屏幕输出

动作:
a 追加,在当前行后添加一行或多行
c 行替换,用c后面的字符串替换原数据行
i 插入,在当前行前插入一行或多行。 d:删除,删除指定的行
p 打印,输出指定的行
s 字串替换,用一个字符串替换另外一个字符串。 格式为行范围s/旧字串/新字串/g (和vim中的替换格式类似)

# 以下均未加-i参数,都不会修改原文件

sed -n '2p' test.txt # 查看文件第2行  
sed -n '2,4p' test.txt # 查看文件第2行到第4行  
sed '2a piaoliang jiushi renxing' test.txt # 在第2行后,加入一行,没加-i,不会修改原文件  
sed '4c last line' test.txt # 将第4行,整行替换  
sed '4s/c/cc/g' test.txt # 将第4行中的所有c替换为cc
sed -e 's/a/A/g;s/b/B/g' test.txt # 将所有的a替换为A,并且将所有b替换为B。多个动作使用分号隔开  

去除字符串两边的空格
echo " abc " | sed 's/^s*//g' | sed 's/s*$//g'

排序与统计

sort
sort [选项] 文件名
-f 忽略大小写
-n 以数值型进行排序,默认使用字符串型排序
-f 反向排序
-t 指定分隔符,默认制表符
-k n[,m] 按照指定的字段范围排序。从第n字段开始,m字段结束(默认到行尾)

sort /etc/passwd
sort -r /etc/passwd
sort -t ":" -k 3,3 /etc/passwd
sort -n -t ":" -k 3,3 /etc/passwd

wc
wc [选项] 文件名
-l 只统计行数
-w 只统计单词数
-m 只统计字符数

流程控制语句

两种判断格式

test -e ./test.txt
[ -e ./test.txt ] # 推荐使用这种

文件判断

按照文件类型判断 常用-d-e-f

选项 作用
-b 文件是否存在,并且是否为块设备文件
-c 是否为字符设备文件
-d 常用选项,目录是否存在
-e 常用选项,文件是否存在
-f 常用选项,普通文件是否存在
-L 是否为符号链接文件
-p 是否为管道文件
-s 文件是否存在,并且是否为非空
-S 文件是否存在,并且是否为套接字文件
# 第一个判断命令正确执行,则输出yes,否则输出no  
[ -e /etc/passwd ] && echo "yes" || echo "no"

按照文件权限进行判断 常用-r-w-x

选项 作用
-r 判断文件是否存在,并且拥有读取权限
-w 判断文件是否存在,并且拥有写权限
-x 判断文件是否存在,并且拥有执行权限
-u 判断文件是否存在,并且拥有SUID权限
-g 判断文件是否存在,并且拥有SGID权限
-k 判断文件是否存在,并且拥有SBit权限

两个文件之间进行比较

选项 作用
文件1 -nt 文件2 文件1的修改时间是否比文件2的新
文件1 -ot 文件2 文件1的修改时间是否比文件2的旧
文件1 -ef 文件2 判断文件1是否和文件2的INODE号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法

整数之间比较

选项 作用
整数1 -eq 整数2 是否相等
-ne 是否不相等
-gt 前一整数数是否大于后一整数
-lt 是否小于
-ge 是否大于等于
-le 是否小于等于

字符串判断

选项 作用
-z 字符串 是否为空
-n 字符串 是否为非空
串1 == 串2 是否相等
串1 != 串2 是否不相等
name=chencye
[ -z "$name" ] && echo "yes" || echo "no"
[ "chencye" == "$name" ] && echo "yes" || echo "no"

# 使用正则,匹配param值中是否包含this
[[ $param =~ "this" ]] && echo "yes" || echo "no"

与或非

选项 作用
判断1 -a 判断2 逻辑与,判断1和判断2都成立,为真
判断1 -o 判断2 逻辑或,判断1和判断2有一个成立,为真
! 判断 逻辑非,使用原始判断式取反

if

fi结尾
then如果放在[]同一行的后面,则需要使用;分开,换行则不需要

单分支

if [ 条件判断 ]; then
    程序
fi

# 或

if [ 条件判断 ]
    then
	程序
fi

多分支

if [ 条件判断1 -a 需同时成立的条件 ]; then
	执行程序1
elif [ 条件判断2 ]; then
	执行程序2
else
	执行程序3
fi

示例1:判断登录用户是否root

#!/bin/bash
name=$(env | grep "USER" | cut -d "=" -f 2)
if [ "$name" == "root" ]; then
    echo "Current user is root."
fi

示例2:判断分区使用率

#!/bin/bash
# 统计根分区使用率

# 获取根分区使用率
rate=$(df -h | grep "/$" | awk '{print $5}' | cut -d "%" -f 1)

if [ $rate -gt 80 ]; then
    echo "Warning! / is full !!"
fi

判断apache是否启动

# 使用这种方式时,注意文件命名不能有httpd
# 可以使用80端口
test=$(ps aux | grep httpd | grep -v grep) 
if [ -n "$test" ]; then
	echo "$(date) httpd is ok!" >> /tmp/autostart-acc.log
else
	/etc/rc.d/init.d/httpd start &> /dev/null
	echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
fi

case

case $变量名 in
    值1 )
	    执行程序1
		;;
	值2 | 值3 )
		执行程序2
		;;
	* )
		如果都不是以上值,则执行此程序
		;;
esac

for

语法1

for 变量 in 值1 值2 值3...
    do
	    程序
	done

# 示例
for i in 1 2 3 4 5
    do
	    echo $i
	done

示例1:批量解压

#!/bin/bash
# tar_for.sh

cd ~/tar
ls *.tar.gz > ls.log
ls *.tgz >> ls.log

for name in $(cat ls.log)
    do
	   tar -zxf $name &> /dev/null
	done
rm -rf ~/tar/ls.log

语法2

for (( 初始值; 循环控制条件; 变量变化 ))
    do
		程序
	done

# 从1加到100
#!/bin/bash
sum=0
for (( i=1; i<=100; i=i+1))
    do
		sum=$(( $sum+$i ))
	done
echo $sum

示例2:批量添加删除指定数据的用户

#!/bin/bash
read -p "Please input user name: " -t 30 name
read -p "Please input the number of users: " -t 30 num
read -p "Please input the password of users: " -t 30 pass

if [ -n "$name" -a -n "$num" -a -n "$pass"]; then
	if [ -n "$(echo $num | grep -P "^d+$")" ]; then
		for (( i=1; i<=$num; i=i+1))
		    do
				/usr/sbin/useradd $name$1 &> /dev/null
				echo $pass | /usr/bin/passwd --stdin $name$i &> /dev/null
			done
	fi
fi
#!/bin/bash
# 删除所有普通用户
for user in $(cat /etc/passwd | grep /bin/bash | grep -v root)
	do
		userdel -r $user
	done

while与until

while: 一直循环,直到条件式不成立

while [ 条件判断式 ]
	do
		程序
	done

until: 一直循环,直到条件式成立

until [ 条件判断式 ]
	do
		程序
	done
原文地址:https://www.cnblogs.com/chencye/p/6123823.html