Shell编程
Posted 李春春_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shell编程相关的知识,希望对你有一定的参考价值。
一、变量1.Shell编程简介
|--shell与其他语言的对比
|--php和java主要实现功能
|--shell简化管理操作,进行系统管理
|--Bash就是Linux的标准shell
|--Linux编程=shell编程=Bash编程
2.bash变量
|--什么是变量与变量分类
|--在Bash中,变量的默认类型都是字符串型
|--变量的分类
|--用户自定义变量:变量名和值都是用户自定义的
|--环境变量:主要保存的是和系统操作环境相关的数据。可以用户自定义,但是对系统生效的环境变量名和变量作用是固定的
|--预定义变量:变量名和作用都是固定的,是系统确定的,用户不能定义只能改值
|--用户自定义变量
|--定义变量
|--变量名称=变量值(=左右不能加空格)
|-- x=5 #就定义了一个叫x的变量
|--注意5是字符,不是数字,不能加减乘除
|-- name="hello world"
|--变量调用
|--在变量名之前加一个$
|--输出变量的值
|--echo $x
|--echo $name
|--变量叠加
|--x=123
|--x="$x"456 --> x=123456
|--x=$x456 --> x=123456789
|--变量查看
|--set #会显示当前系统中所有运行的变量
|--set -u #如果设定此选项,调用未声明变量时会报错(默认无任何提示)
|--删除变量
|--unset 变量名
|--unset name
|--环境变量
|--环境变量与用户自定义变量的区别
|--环境变量是全局变量,用户自定义变量是局部变量
|--用户自定义变量只在当前的shell中生效
|--环境变量在当前shell和这个shell的所有子shell中生效
|--用户可以自定义环境变量,但对系统生效的环境变量名和变量作用是固定的
|--用户自定义环境变量
|--export 变量名=变量值
|--或
|--变量名=变量值
|--export 变量名
|--查看环境变量
|--set #查看所有变量
|--env #查看环境变量
|--删除环境变量
|--unset 环境名
|--常用的环境变量
|--HOSTNAME:主机名
|--SHELL:当前的shell
|--TERM:终端环境
|--HISTSIZE:历史命令条数
|--SSH_CLIENT:当前操作环境是用ssh连接的,这里记录客户端ip
|--SSH_TTY:ssh连接的终端是pts/1
|--USER:当前登录的用户
|--PATH:系统搜索命令的路径
|--要想直接通过脚本名执行自己的脚本
|--将脚本拷贝至PATH中的任意目录下(不建议这样做),例如
|--cp hello.sh /bin/
|--将脚本所在目录添加到PATH变量中,例如
|--PATH="$PATH":/root/sh 但系统重启后失效
|--要想永久生效,需要修改环境变量配置文件
|--PS1:命令提示符设置
|--\\d:显示日期,格式为"星期 月 日"
|--\\H:显示完整的主机名
|--\\t:显示 24 小时制时间,格式为"HH:MM:SS"
|--\\A:显示 24 小时制时间,格式为"HH:MM"
|--\\u:显示当前用户名
|--\\w:显示当前所在目录的完整名称
|--\\W:显示当前所在目录的最后一个目录
|--\\$:提示符。root 用户为"#",普通用户为"$"
|--PS1='[\\u@\\A \\w]\\$ '
|--语系变量
|--locale 把系统语系赋给变量
|--LANG:定义系统主语系的变量
|--LC_ALL:定于整体语系
|--echo $LANG #当前语系环境
|--locale -a #支持其他的语系
|--查询系统默认语系
|--cat /etc/sysconfig/i18n #下次开机之后支持语系环境
|--位置参数变量 --> 只适合写这个脚本的作者使用,只有他知道有几个参数
|--$n:n为数字,$0代表命令本身,$1-$9代表第一到第九个参数,十以上的参数需要用大括号包含,如$10
|--$*:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体
|--$@:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待
|--$#:这个变量代表命令行中所有参数的个数
|--基本的bash脚本、for循环语句
|--预定义变量
|--$?:最后一次执行的命令的返回状态
|--如果这个变量的值为0,证明上一个命令正确执行
|--如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了
|--$$:当前进程的进程号(PID)
|--$!:后台最后一个运行的进程的进程号(PID)
|--接收键盘输入 --> 适合第三方用户使用
|--read [选项] [变量名]
|-- -p "提示信息":在等待read输入时,输出提示信息
|-- -t 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间
|-- -n 字符数:read命令只接受指定的字符数,就会执行
|-- -s 隐藏输入的数据,适用于机密信息的输入
二、运算符
1.declare命令
|--shell变量的缺点
|--弱类型
|--不声明变量类型,linux中默认都是字符串型,如果想进行运算,必须进行声明
|--declare声明变量类型
|--declare [+/-][选项]变量名
|-- -:给变量设定类型属性
|-- +:取消
|-- -a:数组
|-- -i:整型
|-- -x:环境变量
|-- -r:只读
|-- -p:显示指定变量的被生命类型
|--declare -i c=$a+$b #声明c为整型
|--declare -p c #查看c的数据类型
2.数值运算方法
|--dd=$(($aa+$bb))
|--dd=$(expr $aa + $bb) #加号两边要有两个空格
|--dd=$[$aa+$bb]
|--gg = $(date) #变量名 = $(命令) 这种格式是先执行括号里面的命令 再把结果送给变量
3.变量测试
|--变量测试方法,只对shell生效,其他一般语言都不存在
|--变量测试在脚本优化时使用
|--好处:代码精简
|--坏处:不好记忆和理解
|--见视频中的表格
三、环境变量配置文件
1.环境变量配置文件简介
|--环境变量配置文件中主要是定义对系统操作环境生效的系统默认环境变量,如PATH等
|--修改配置文件后,必须注销重新登陆才会生效
|--或者使用:source 配置文件
|--或者使用:. 配置文件
|--环境变量配置文件
|--/etc/profile
|--/etc/profile.d/*.sh
|--~/.bash_profile
|--~/.bashrc
|--/etc/bashrc
2.环境变量配置文件的功能
|--有登陆过程和没有登录过程的shell调用不一样
|--有登陆在/etc/profile开始
|--/etc/profile-->/etc/profile.d/*.sh-->/etc/profile.d/lang.sh-->/etc/sysconfig/i18n ...
|--/etc/profile-->~/.bash_profile-->~/.bashrc-->/etc/bashrc-->命令提示符
|--没有登录在/etc/bashrc,不过没有登录的情况很少,基本没有见过
|--/etc/bashrc-->/etc/profile.d/*.sh-->/etc/profile.d/lang.sh-->/etc/sysconfig/i18n ...
|--PATH环境变量写在哪里其实无所谓的,都会被调用到
|--如果提示符变成了一个bash5.2#的吊样子,说明之前的配置文件至少丢了一个
3.其他环境变量配置文件
|--注销时生效的环境变量配置文件
|--~/.bash_logout
|--保存在文件中的历史命令
|--~/.bash_history
|--本地终端欢迎信息
|--/etc/issue
|--有一些转义符
|--远程终端欢迎信息(默认是不启用的,不支持转义符)
|--/etc/issue.net
|--在/etc/ssh/sshd_config决定,加入"Banner /etc/issue.net"行才能生效(记得重启SSH服务:service sshd restart)
|--登陆后欢迎信息
|--/etc/motd
|--issue是登陆之前生效的,motd是登陆之后生效的,建议写在motd中
|--不管是本地还是远程登录,都会显示此欢迎信息
四、正则表达式与字符处理
1.正则表达式
|--正则表达式主要用于字符串的模式分割、匹配(最重要的功能)、查找及替换操作
|--通配符
|--* 匹配任意内容
|--? 匹配任意一个内容
|--[] 匹配中括号中的一个字符
|--正则和通配符的区别
|--正则表达式用来在文件中匹配符合条件的字符串,通配符用来匹配文件名
|--前者是包含匹配,后者是完全匹配
|--搜索字符串的命令能够识别正则grep/awk/sed,搜索文件的命令能够识别通配符ls/find/cp
|--基础正则表达式
|--* #前一个字符匹配0次或任意多次
|--grep "aa*" abc #匹配abc文件中内容,至少包含一个a的行输出
|--. #匹配除了换行符外任意一个字符
|--grep "s..d" abc #匹配s和d之间一定有两个字符的单词
|--grep "s.*d" abc #匹配在s和d字母之间有任意字符
|--^ #匹配行首。例如:^hello会匹配hello开头的行
|--$ #匹配行尾。例如:hello$会匹配以hell结尾的行
|--grep -n "^$" abc #匹配空白行,并显示行号
|--[] 匹配中括号中指定的任意一个字符,只匹配一个字符
|--[aeiou]匹配任意一个元音字母
|--[0-9]匹配任意一位数字
|--[a-z][0-9]匹配小写字母和一位数字构成的两位字符
|--^[a-z]匹配用小写字母开头的行
|--[^] 匹配除中括号的字符意外的任意一个字符
|--[^0-9]匹配任意一位非数字字符
|--[^a-z]表示任意一位非小写字母
|--^[^a-z]匹配不用小写字母开头的行
|--^[^a-zA-Z]匹配不用字母开头的行
|--\\ #转义符
|--grep -n "\\.$" abc #匹配使用"."结尾的行
|--\\n\\ #表示其前面的字符恰好连续出现n次
|--a\\3\\ 表示字母a至少重复3次
|--[0-9]\\4\\匹配包含连续的四个数字的字符串
|--[1][3-8][0-9]\\9\\匹配手机号码
|--\\n,\\ #表示其前面的字符出现不小于n次
|--[0-9]\\2,\\表示两位及以上的数字
|--^[1-9]\\3,\\[a-z] 匹配至少用3个连续数字开头,并且包含小写字母的行
|--\\n,m\\ #表示其前面的字符至少出现n次,最多出现m次
|--[a-z]\\6,8\\匹配包含有6到8位的小写字母
|--例子
|--匹配时间格式:grep "[0-9]\\4\\-[0-9]\\2\\-[0-9]\\2\\" test.txt
|--匹配IP地址: grep "[0-9]\\1,3\\\\.[0-9]\\1,3\\\\.[0-9]\\1,3\\\\.[0-9]\\1,3\\" test.txt
|--IP地址最大为255.255.255.255,所以这个正则只能用于从文档中提取IP地址,不能用来写入
2.字符截取命令
|--cut字段提取命令
|--grep是行提取命令、cut是列提取命令
|--搜寻系统中所有的普通用户
|--grep "/bin/bash" /etc/passwd | grep -v "root"
|--搜寻上述结果的:分割的字符串的第一列的用户名
|--cut [选项] 文件名
|-- -f 列号:提取第几列(从1开始)
|-- -d 分隔符:按照指定分隔符分割列 默认为tab
|--cut -f 2,4 student.txt
|--例如:提取非root登录用户用户名
|--grep "/bin/bash" /etc/passwd | grep -v "root" | cut -f 1 -d ":"
|--但是cut无法只能分割空格
|--df -h | cut -d " " -f 1,3:由于df由多个空格分割,无法按照预期显示
|--printf命令
|--printf '输出类型输出格式' 输出内容
|--输出类型
|--%ns:输出字符串
|--%ni:输出整数
|--%m.nf:输出浮点数
|--输出格式
|--\\n:换行
|--\\t:Tab
|--\\r:回车
|--\\b:退格
|--输出文件中的字符串:
|--printf "%s\\t%s\\t%s\\t%s\\n" $(cat student.txt)
|--命令awk支持print和printf
|--命令print会在每个输出之后自动加入一个换行符,但是Linux默认没有print命令
|--命令printf不会自动加入换行符
|--awk命令
|--awk '条件1动作1条件2动作2' 文件名
|--awk 'printf $2 "\\t" $4 "\\n"' student.txt
|--df -h | awk 'print $1 "\\t" $3'
|--df -h | grep "/dev/sda5" | awk 'print $5' | cut -d "%" -f 1
|--BEGIN、END
|--awk 'BEGINprint "test"print $2 "\\t" $4' student.txt
|--cat /etc/passwd | grep "/bin/bash" | awk 'BEGINFS=":"print $1"\\t"$3'
|--关系运算符
|--cat student.txt | grep -v "Name" | awk '$4>=70print $2'
|--sed字符串替换命令
|--sed [选项] '[动作]' 文件名
|--选项
|-- -n 只输出经过sed处理过的行到屏幕(不加的话会把所有数据都输出到屏幕)
|-- -e 允许一次应用多个动作
|-- -i 直接修改文件,并且不由屏幕输出
|--动作
|-- a : 追加,在当前行后添加一行或多行
|-- c : 整行替换
|-- i : 插入,在当前行前插入一行或多行
|-- d : 删除
|-- p : 打印
|-- s : 字串替换(替换格式与vim中的类似) '行范围s/旧字串/新字串/g'
|--例如:
|--sed -n '2p' student.txt #查看文件第二行
|--sed '2,4d' student.txt #删除2至4行显示(注意:并没有删除文件中的内容,只是更改了输出)
|--sed '2a piaoliang' student.txt #在第二行之后追加(并没有改变文件)
|--sed '2i piaoliang' student.txt #在第二行之前追加(并没有改变文件)
|--sed '4c avcang' student.txt #替换整行(并没有修改文件)
|--sed '3s/60/99/g' student.txt #在第三行中,把60换成99
|--sed -i '3s/60/99/g' student.txt #sed操作的数据直接写入文件
|--sed -e 's/fengj//g;s/cang//g' student.txt #同时把"fengj"和"cang"替换为空
3.字符处理命令
|--sort排序命令
|--sort [选项] 文件名
|-- -f:忽略大小写
|-- -n:以数值型进行排序,默认使用字符串型排序
|-- -r:反向排序
|-- -t:指定分隔符,默认是制表符
|-- -k n[,m]:按照指定的字段范围排序,从第n个字段到第m个字段(默认到行尾)
|-- 例如
|--sort /etc/passwd #排序用户信息文件
|--sort -n -t ":" -k 3,3 /etc/passwd #指定分隔符是":",用第三字段按照数值型排序
|--wc统计命令
|--wc [选项] 文件名
|-- -l:只统计行数
|-- -w:只统计单词数
|-- -m:只统计字符数
五、条件判断与流程控制语句
1.条件判断式语句
|--按文件类型进行判断
|--选项
|-- -d:判断该文件是否存在,并且是否为目录文件(是目录为真)
|-- -e:判断该文件是否存在 (存在为真)
|-- -f:判断该文件是否存在,并且是否为普通文件(是普通文件为真)
|--判断格式
|--test -e /root/install.log
|--[ -e /root/install.log ]
|--例如
|--[ -e student.txt ] && echo "yes" || echo "no"
|--按文件权限进行判断
|--选项
|-- -r:判断该文件是否存在,并且该文件是否有读权限
|-- -w:判断该文件是否存在,并且该文件是否有写权限
|-- -x:判断该文件是否存在,并且该文件是否有执行权限
|--举例
|--[ -w student.txt ] && echo yes || echo no
|--两个文件之间进行比较
|--选项
|--[ file1 -nt file2 ]:判断文件1的修改时间是否比文件2的新
|--[ file1 -ot file2 ]:判断文件1的修改时间是否比文件2的旧
|--[ file1 -ef file2 ]:判断文件1是否比文件2的Inode号一致,可以理解为两个文件是否为同一个文件
|--例如:
|--ln /root/student.txt /tmp/stu.txt #创建一个硬链接
|--[ /root/student.txt -ef /tmp/stu.txt ] && echo yes || echo no #用test测试一下
|--两个整数之间进行比较
|--格式:
|--[ num1 -eq num2 ]:判断整数1是否和整数2相等
|--[ num1 -ne num2 ]:判断整数1是否和整数2不相等
|--[ num1 -gt num2 ]:判断整数1是否大于整数2
|--[ num1 -lt num2 ]:判断整数1是否小于整数2
|--[ num1 -ge num2 ]:判断整数1是否大于或等于整数2
|--[ num1 -le num2 ]:判断整数1是否小于或等于整数2
|--例如
|--[ 23 -ge 22 ] && echo yes || echo no #23是否大于等于22
|--字符串的判断
|--格式
|--[ -z 字符串 ]:判断字符串是否为空
|--[ -n 字符串 ]:判断字符串是否为非空
|--[ 字符串1==字符串2 ]:判断字符串1是否和字符串2相等
|--[ 字符串1!=字符串2 ]:判断字符串1是否和字符串2不相等
|--注意整数判断中的-eq和字符判断中的==不同之处
|--例如
|--[ "$aa" == "$bb" ] &&echo yes || echo no #判断两个字符串是否相等
|--多重条件判断
|--格式
|--[ 判断1 -a 判断2 ]:逻辑与,判断1和判断2都成立,最终结果为真
|--[ 判断1 -o 判断2 ]:逻辑或,判断1和判断2有一个成立,最终结果为真
|--[ ! 判断 ]:逻辑非,使原始的判断式取反
|--例如
|--aa=11
|--[ -n "$aa" -a "$aa" -gt 23 ] && echo yes || echo no #no
2.if语句
|--单分支if语句
|--格式
|--if [ 条件判断式 ]; then
|-- 程序
|--fi
|--例如
|--判断登录的用户是否是root
|--见文件:/root/sh/if1.sh
|--判断分区使用率
|--见文件:/root/sh/if2.sh
|--双分支if语句
|--格式
|--if [ 条件判断式 ]
|-- then
|-- 条件成立时,执行的程序
|-- else
|-- 条件不成立时,执行的程序
|--fi
|--例如
|--判断输入的是否是一个目录
|--/root/sh/if3.sh
|--判断Apache服务是否启动
|--/root/sh/if4.sh
|--多分支if语句
|--格式
|--if [ 条件判断式1 ]
|-- then
|-- 当条件判断式1成立时,执行程序1
使用jsch连接到linux上,然后执行shell命令,返回的结果中存在乱码,各位大大怎么解决?