1、一个shell脚本运行必须要拥有r和x权限; chamod u+x 1.txt
2、运行一个shell脚本的3个步骤:
(1)启动bash解释器
(2)bash把文件内容从硬盘读入内存
(3)bash把读入到内存的内容进行语法解释,控制操作系统执行shell代码
写脚本时候,应该规避好一些交互式的命令
3、运行脚本的有2中方法:
(1)交互式环境:每敲一个命令执行一次,但是不能永久保存
(2)文件内:一次全部执行,但是会永久保存
4、在当前界面运行脚本,不开启新进程
. 1.txt 在当前进程 或者 source 1.txt
bash 1.txt 开启了一个新进程
./ 1.txt 开启了新的一个进程
1、变量的定义 变量需要先定义,后引用 per=36 #定义变量的时候,=两边不能有空格,否则报错 @@@ echo $per echo ${per}G # 引用变量最好用这样的格式 @@@
2、变量名的使用规则 用字母,数字,下划线组成;不可用中文,以及一些既有的命令
3、变量值的类型 int整型 name=10 fault浮点型 name=3.14 str字符串 name="hello world"
4、特殊的符号 @@@@ "":双引号 '':单引号的硬引用; 引号内的符号均无特殊意义 ``:取里面命令的结果 $():取里面命令的结果,区别于上条的是,本条可以进行嵌套: $(命令 $(命令)) \:右斜杠 例子: a=10 echo "$a" #结果是10 echo '$a' #结果是$10 echo "\$a" #结果是$a #取消特殊字符的意义 echo $(+date %Y-%m-%y).txt
5、变量的作用域(生效范围) (1)全局变量:定义的变量只在该进程有效 例子: per=36 vim 1.txt (echo "$per") echo "$per" #有结果 bash 1.txt #没有结果 source 1.txt #有结果 export per ; bash 1.txt #有结果 (继承了per的结果给子进程,父进程看不到) @@@@ export的是遗传,子子孙孙进程都可以看待;但是子进程开启的变量,父进程不可以引用; (2)变量先从局部变量找,没有了再从父辈遗传的找,再从环境变量里找 (3)添加环境变量 #登录时候就自动启动 * 对/root 临时添加环境变量 PATH=$PATH:/root * 对/root 永久添加环境变量,并给到所有的子进程 vim /etc/profile PATH=$PATH:/root export PATH env 查看所有的环境变量 set 查看所有的变量,临时的也可以看到 (4)删除变量 unset per
元字符是被shell解释器解释,而正则表达式是被命令解释
1、{}、[]和!的应用: touch {1..5}.txt touch {a..e}.txt ls [0-9].txt ls [!0-9].txt
2、变量间的运算 (1)整型和浮点型的运算 ***expr 变量间不做什么的情况下只是整型int的运算 $a + $b 特别注意中间的空格 @@@@@ c=`expr $a + $b` expr 支持 + - / % 除的话取整数,%为取余 @@@@@ 乘法是:expr 5 \* 3 @@@@@ ***bc echo " 3.14 < 3.16 " | bc (2)let x++ 等于在原来变量上加1不支持多加 没有此变量时候默认就为0 a=10; echo `expr $a + 1 ` (3)& 1个&放在命令的结尾表示后台运行 2个&&放在2个命令之间,表示并且的意思;只有左边的命令成功的情况下才可以运行右边的命令 &> 无论结果是否正确都重定向 (4)|| 或者的意思 wssfsf || ls 左边命令错误时,右边命令才运行; 也就是要不左边成立,要不右边成立 ls || pwd 此时只运行ls命令 (5); 不管命令是否正确都会运行 asfg ; pwd (6)() *取命令的结果:echo $(expr $a + $b) *嵌套取命令结果,或者进行运算:$(命令 $(命令)) > >= < <= ==(等于) !=(不等于) &&(and) ||(or) 例子: x=100 (( $x == 100 )) ; echo $? #结果是1 (( $x != 100 || 100 >= 10 )) ; echo $? #结果是0 (7)[] 类似于test命令 *test test $x -eq 5 ; echo $? *[] *进行整型运算:echo $[10 + 2] *进程过滤时候:ps -aux | grep [p]ing 去掉这个命令执行时候的进程 *判断字符值是否相同;例子如下 name="egon" ; [ $name = "egon" ] echo $? #结果为0是真,结果为1是假的 **小脚本(用户登录程序:要求只有用户名和密码对输出ok,其他ng): [root@local-test var]# cat 1.txt #!/bin/bash read -p "yourname:" name read -p "passwd:" passwd [ $name = "zzyy" ] && [ $passwd = 123 ] && echo ok || echo NG *判断数字值是否相同;例子如下 @@@@@ *判断数字值相等:[ 10 -eq 10 ] && echo $? 结果是0 *判断数字值大于:[ 10 -gt 8 ] && echo $? 结果是0 *判断数字值大于等于:[ 10 -ge 12] ; echo $? 结果是1 *判断数字值小于:[ 10 -lt 8 ] ; echo $? 结果是0 *判断数字值小于等于:[ 10 -le 12] ; echo $? 结果是1 *判断数字值不等于:[ 10 -ne 12] ; echo $? 结果是0 *判断是否有一般文件:[ -f /root/2.txt ] ; echo $? 判断是否有这个普通文件2.txt *判断是否有这个文件:[ -e /root/2.txt ] ; echo #? 判断是否有这个文件2.txt * (8)? 指定一个字符 ls ?.txt ; ls ??txt 查找所有a到Z的文件 ls /etc/[a-Z].txt (9) : 结果永远为真 : ; echo $? #结果是0 总结: ; 不管左右的命令是否成功都运行,错误就报错 && 只有左边的成功时,右边的才会运行 || 或者左边的运行。或者右边的运行
3、如何进行小数的运算 (1)yum install bc -y (2)echo $(echo "scale=2; 3/10" | bc | cut -d '.' -f2 )% @@@@@ 结果:30% scale=2取小数点两位,后执行命令3/10,后bc做小数,后以.分割取出来点后的2位数字 echo " 3.14 < 3.16 " | bc
4、awk和bc的小例子 a=free | awk 'NR==2{print $NF}' #拿出实际使用的内存 awk必须是单引号 b=free | awk 'NR==2{print $2}' #总的内存 echo $(echo "scale=2; $a / $b " | bc | cut -d '.' -f2)% #计算出%比 echo `echo "scale=2; $a / $b " |bc | cut -d "." -f2 `%
写脚本的时候注意事项: 对数据的增改删的时候需要 (1)set -o errexit 脚本有错误的时候不运行退出 [root@local-test ~]# cat 1.txt #!/bin/bash set -o errexit echo 111 echo 222 echo 333 afsdfgdg echo 444 [root@local-test ~]# bash 1.txt 111 222 333 1.txt: line 7: afsdfgdg: command not found (2)set -o nounset 只要变量不存在就退出 echo $yyy yyy之前不被定义 (3)set -o pippefail addsv| echo 123
egon--元字符总结 1、`` 与$():取命令的结果 [root@localhost ~]# echo `pwd` /root [root@localhost ~]# echo $(pwd) /root 不一样的地方在于$()可以嵌套,而``不能嵌套 [root@localhost ~]# echo $(ls $(pwd)) # 练习 [root@aliyun test]# touch $(date +%F)_bak.tar.gz [root@aliyun test]# ls 2020-08-24_bak.tar.gz 2、~家目录 3、.与.. 4、!调用历史命令、取反 # 1、调用历史命令 [root@egon ~]# !1066 [root@egon ~]# !ls # 匹配最近的一次历史命令 # 2、取反1:对命令的结果取反 [root@egon ~]# ! pwd /root [root@egon ~]# echo $? 1 # 3、取反2:效果与^雷同 [root@localhost ~]# touch /test/{1.txt,2.txt,a.txt,aaa_bbb.txt} [root@localhost ~]# find /test ! -name 1.txt /test /test/2.txt /test/a.txt /test/aaa_bbb.txt [root@localhost ~]# ls /test/[!0-9].txt # .txt前只有一个字符,但是非数字 /test/a.txt [root@localhost ~]# ls /test/[^0-9].txt # .txt前只有一个字符,但是非数字 /test/a.txt [root@aliyun test]# ls -a /etc/skel/.[!.]* 5、@无特殊意义 6、#注释 7、$取变量值 (1)[root@localhost ~]# x=1 [root@localhost ~]# echo $x (2)%、-、+运算符,注意%可以与jobs配合“kill %工作号”杀后台进程。-减号还有区间及cd -回到上一级的意思 # 数学运算 # 1、bc是比较常用的linux计算工具了,而且支持浮点运算: [root@localhost ~]# res=`echo 1+1 | bc` [root@localhost ~]# res=`echo 1.2+1.3|bc` [root@localhost ~]# res=`echo "scale=2;5.0/3.0"|bc` [root@localhost ~]# echo $res 2 取余 [root@localhost ~]# res=`echo 10 % 3 | bc` [root@localhost ~]# echo $res [root@localhost ~]# res=`echo 5.0+3.0|bc` [root@localhost ~]# echo $res 3、expr不支持浮点数计算。而且要注意数字与运算符中的空格 [root@localhost ~]# res=`expr 5 / 3` # 不支持浮点计算 [root@localhost ~]# echo $res [root@localhost ~]# res=`expr 1+1` # 注意:要有空格 [root@localhost ~]# echo $res [root@localhost ~]# res=`expr 1 + 1` [root@localhost ~]# echo $res [root@localhost ~]# res=`expr 5 \* 3` # 在expr中*号要转义才能用,否则报语法错 4、$(()) 同expr,不支持浮点数运算 [root@localhost ~]# echo $((1+1)) [root@localhost ~]# echo $((1.0+2.0)) -bash: 1.0+2.0: 语法错误: 无效的算术运算符 (错误符号是 ".0+2.0") 5、$[]同expr以及$(()),不支持浮点运算 [root@localhost ~]# x=1 [root@localhost ~]# echo $[$x+1] 6、let 不支持浮点数运算,而且不支持直接输出,只能赋值 [root@localhost ~]# let res=1+1 [root@localhost ~]# echo $res 2 [root@localhost ~]# [root@localhost ~]# let res=50/5 [root@localhost ~]# echo $res 10 [root@localhost ~]# let c=1.3*3 -bash: let: c=1.3*3: 语法错误: 无效的算术运算符 (错误符号是 ".3*3" [root@aliyun test]# x=1 [root@aliyun test]# let x+=10 [root@aliyun test]# echo $x 11 8、^同!一样 9、&后台运行 [root@localhost home]# echo "hello";sleep 3;echo "world" & && 两个命令之间,前面那个运行成功后面才运行 10、*任意多个字符 [root@localhost ~]# touch 1.txt 2.txt aa.txt aaa.txt [root@localhost ~]# rm -rf *.txt [root@localhost ~]# touch 1.txt 2.txt aa.txt aaa.txt a1c.txt [root@localhost ~]# ls *.txt 1.txt 2.txt a1c.txt aaa.txt aa.txt 11、()在子shell中执行 [root@localhost ~]# (x=1) [root@localhost ~]# echo $x 应用 [root@localhost ~]# (umask 066;touch a.txt) # umask的设置只在子shell中有效 [root@localhost ~]# ll a.txt -rw-------. 1 root root 0 8月 13 15:22 a.txt [root@localhost ~]# touch b.txt [root@localhost ~]# ll b.txt -rw-r--r--. 1 root root 0 8月 13 15:23 b.txt 10、_下划线:无特殊意义,可以用于名字的声明 [root@localhost ~]# tar -czvf `date +%F_%H:%M:%S`_bak.tar.gz /etc/ 11、=赋值,==判断相等性 [root@localhost ~]# [ 1 == 1 ] # 条件1 == 1的左右两边必须有空格 [root@localhost ~]# echo $? # 判断上一条命令的结果是否为真,0=》true 0 12、|管道:把一个进程的处理结果传递给另外一个进程 [root@localhost ~]# ps aux | grep python |管道命令的作用,是将左侧命令的标准输出转换为标准输入,提供给右侧命令作为参数。但是,大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,这导致无法用管道命令传递参数。比如echo命令就不接受管道传参。 $ echo "hello world" | echo xargs命令的作用,是将标准输入转为命令行参数,例如 $ echo "hello world" | xargs echo hello world [root@localhost ~]# find /home/ -type d -name "test*" |xargs ls 1.txt 2.txt 3.txt [root@localhost ~]# ls /home/test 1.txt 2.txt 3.txt 13、\转义特殊字符 [root@localhost ~]# mkdir a\ b.txt # 虽然可以,但不推荐 [root@localhost ~]# ll 总用量 0 drwxr-xr-x. 2 root root 6 8月 13 15:35 a b.txt [root@localhost ~]# echo $RMB # 默认会当成变量 [root@localhost ~]# echo '$RMB' # 取消特殊意义 $RMB [root@localhost ~]# echo \$RMB # 取消特殊意义 $RMB 14、[]条件测试,后续会详细介绍 [root@localhost ~]# name="egon" [root@localhost ~]# [ $name == "egon" ];echo $? 0 [root@localhost ~]# name="adf" [root@localhost ~]# [ $name == "egon" ];echo $? 1 [root@localhost ~]# [ -d /test ];echo $? 0 [root@localhost ~]# 15、引号 '' 强引用(在单引号中都视为普通字符) " " 弱引用 (在双引号中保留变量) [root@localhost ~]# x=111 [root@localhost ~]# echo "$x" 111 [root@localhost ~]# echo '$x' $x [roo 16、;与&&与||连接多条命令 [root@localhost home]# gagaga;ls # 不论前一条命令运行成功与否,都会执行后续命令 bash: gagaga: 未找到命令... egon [root@localhost home]# gagaga && ls # 只有前一条命令执行成功,才会执行后续命令 bash: gagaga: 未找到命令... [root@localhost home]# ls /test || mkdir /test # 前一条命令执行不成功才会执行后续命令 0.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt 17、:空命令,真值 [root@egon ~]# : [root@egon ~]# echo $? 0 18、/路径分隔符 19、{}循环列表 [root@localhost home]# touch /test/{0..9}.txt [root@localhost home]# ls /test/ 0.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt [root@localhost ~]# touch {1..3}{a..d}.txt [root@localhost ~]# ls 1a.txt 1b.txt 1c.txt 1d.txt 2a.txt 2b.txt 2c.txt 2d.txt 3a.txt 3b.txt 3c.txt 3d.txt [root@egon ~]# x=100 [root@egon ~]# echo ${x}% # 控制变量名的范围 100% [root@egon ~]# [root@egon ~]# echo $xrmb [root@egon ~]# echo ${x}rmb 100rmb 20、重定向 > >> 输出重定向 < << 输入重定向 > 覆盖 >> 追加 [root@localhost home]# cat >> a.txt << EOF > 111 > 222 > 333 > EOF 0标准输入、1标准正确输出、2标准错误输出,&标准正确和错误输出 [root@localhost home]# pwd 1>a.txt [root@localhost home]# cat a.txt /home [root@localhost home]# gagag 2>a.txt [root@localhost home]# cat a.txt bash: gagag: 未找到命令... [root@localhost home]# gagaga &>/dev/null < << 输入重定向 [root@localhost ~]# mysql -uroot -p123 < bbs.sql [root@localhost home]# grep root < /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [root@localhost home]# dd if=/dev/zero of=/a.txt bs=1M count=10 记录了10+0 的读入 记录了10+0 的写出 10485760字节(10 MB)已复制,0.024387 秒,430 MB/秒 [root@localhost home]# dd </dev/zero >/b.txt bs=1M count=10 记录了10+0 的读入 记录了10+0 的写出 10485760字节(10 MB)已复制,0.0202365 秒,518 MB/秒 [root@localhost home]# ll /a.txt -rw-r--r--. 1 root root 10485760 8月 13 16:02 /a.txt [root@localhost home]# ll /b.txt -rw-r--r--. 1 root root 10485760 8月 13 16:03 /b.txt 21、?任意一个字符 [root@localhost ~]# ls ??.txt aa.txt [root@localhost ~]# ls a?c.txt a1c.txt [root@localhost ~]# rm -rf *.txt 22、范围中的任意一个字符 [12] [ac] [a-z] [0-9] [root@localhost ~]# touch a1c a2c axc aXc axd [root@localhost ~]# ls a?c a1c a2c axc aXc [root@localhost ~]# ls a[1x]c a1c axc [root@localhost ~]# ls a[a-z]c axc aXc [root@localhost ~]# ls a[A-Z]c # 不区分大小写 axc aXc [root@localhost ~]# ls a[x]c axc [root@localhost ~]# ls a[X]c aXc [root@localhost ~]# ls a[0-9]c a1c a2c [root@localhost ~]# ls /dev/sd[a-z]* /dev/sda /dev/sda1 /dev/sda2 /dev/sda3 /dev/sdb1
if的语法: 什么是if判断,为什么要用? 根据条件的真假来决定去做什么事情,要用是因为要让计算机代替人去做判断 1. 语法 ***完整语法 if 条件 ; then # 如果条件是命令,一般把它丢到空里/dev/null 代码1 #如果条件1成立下面的elif不允许 代码2 elif 条件 ; then #如果条件1不成立,本条件运行 代码1 代码2 elif 条件 ; then 代码1 代码2 else 代码1 代码2 fi #if的反过来 ***单分支语法 if 条件 ; then 代码1 代码2 fi ***单分支语法 if 条件 ; then 代码1 代码2 else 代码1 代码2 fi 判断成绩的小例子: #!/bin/bash read -p "your score:" score if [ $score -gt 90 ] ;then echo "excellent" elif [ $score -ge 60 ] ; then echo "good" else echo "bad" fi
while循环 * true和:表示为真;开始和结束以do和done为准;结束循环可以是自然结束和break 命令格式: while 条件 do 命令1 命令2 done (1)脚本中的运行 登录的小例子: #!/bin/bash while : do read -p "yourname:" name read -p "passwd:" passwd if [ $name = "zz" ] && [ $passwd = 123 ] ; then echo "login ok" break else echo "fluse" fi done 打印10以内的数字: #!/bin/bash count=0 #中间不能有空格 while [ $count -le 10 ] do echo $count (( count ++ )) done (2)在命令行中写入一行: while 条件 ; do 命令1 ;命令2 ; done 实时显示一些状态 while true ; do ifconfig; sleep 0.5;clear; done clear就是清屏
for 循环应用 for循环在固定循环次数的情况下优势强 #!/bin/bash for i in `seq 0 3` do if [ $i -gt 2 ]; then break fi echo $i 备注:seq 0 5 和{0..5} 是一个效果;都是0 1 2 3 4 5 ping一个段内的所有网址,看是否ping通 #!/bin/bash for i in {2..100} do (ping -c1 192.168.15.$i &>/dev/null if [ $? -eq 0 ]; then echo "192.168.15.$i up" else echo "192.168.15.$i down" fi) & done 备注:在命令后加上&,是使其在后台运行,能很大程度的提升运行速度
批量修改文件名
for name in ls *.txt
;do mv $name ${name%.txt}.log;done
rename log txt *