Linux-Shell编程

张开发
2026/4/11 8:54:48 15 分钟阅读

分享文章

Linux-Shell编程
Shell是一个命令行解释器它接收应用程序/用户命令然后调用操作系统内核。写一个hello.sh脚本1.mkdir scripts2.cd scripts3.touch hello.sh4.vim hello.sh#!/bin/bash echo hello,world5.bash hello.sh另外启用一个bash进程5.chmod x /scripts/hello.sh /scripts/hello.sh必须要用相对或绝对路径不能进入scripts文件夹再执行 ./hello.sh最常用5.前两种都启用子shell进程source hello.sh . hello.sh不启用子shell进程没有父子shell嵌套关系用ps -f可以查看bash进程数量用exit可以退出子bash进程。开子shell与不开子shell的区别就在于环境变量的继承关系如在子shell中设置的当前变量父shell是不可见的。echo $HOME查看HOME系统变量env | less查看所有系统全局变量set | less查看定义的所有变量自定义变量在子shell更改变量不影响父shell。全局环境变量名字建议大写。a2等号两边不能加空格echo $ashello, world变量的值有空格需要使用双引号括起来。echo $sexport s升级成全局变量a$((15))可以进行符号运算 a$[15]echo $areadonly b5定义一个只读变量b10报错只读unset a删除变量aunset b删除不了只读特殊变量1.$n 功能描述n为数字$0代表该脚本名称$1-$9代表第一到第九个参数十以上的参数需要用大括号包含如${10}vim hello.sh#!/bin/bash echo hello, world echo hello, $1./hello.sh xiaoming将xiaoming填入$1vim parameter.sh单引号就不会把里面的$认为是变量而是原封不动输出。#!/bin/bash echo ----------$n----------- echo script name:$0 echo 1st parameter:$1 echo 2nd parameter:$2chmod x parameter.sh./parameter.sh abc def2.$#功能描述获取所有输入参数个数常用于循环判断参数的个数是否正确以及加强脚本的健壮性。vim parameter.sh#!/bin/bash echo ----------$n----------- echo script name:$0 echo 1st parameter:$1 echo 2nd parameter:$2 echo ----------$#----------- echo parameter numbers:$#./parameter.sh abc def3.$*功能描述这个变量代表命令行中所有的参数$*把所有的参数看成一个整体$功能描述这个变量也代表命令行中所有的参数不过$把每个参数区分对待vim parameter.sh#!/bin/bash echo ----------$n----------- echo script name:$0 echo 1st parameter:$1 echo 2nd parameter:$2 echo ----------$#----------- echo parameter numbers:$# echo ----------$*----------- echo $* echo ----------$----------- echo $./parameter.sh abc def4.$功能描述最后一次执行的命令的返回状态。如果这个变量的值为0证明上一个命令正确执行如果这个变量的值为非0具体是哪个数由命令自己来决定则证明上一个命令执行不正确了。echo $?接上面代码结果为0parameter.sh报错echo $?非0运算符echo $[5 * 2]s$[(23) * 4]echo $scd /scriptsvim add.sh#!/bin/bash sum$[$1 $2] echo sum$sumchmod x add.sh./add.sh 25 25条件判断[ condition ]注意condition前后要有空格注意条件非空即为 true[ happygame ]返回true[ ]返回 false。[ $a Hello ]等号两边需要空格否则识别成一个值echo $?如果a是Hello则结果为0[ $a ! Hello ]echo $?a是Hello则结果为1两个整数之间比较-eq等于equal)-ne不等于(not equal)-lt小于(less than)-le小于等于(less equal)-gt大于(greater than)-ge大于等于greater equal)[ 2 -lt 8 ]echo $?结果为0[ 2 -gt 8 ]echo $?结果为1按照文件权限进行判断-r有读的权限read-w有写的权限write-x有执行的权限(execute)touch test[ -r test ]echo $?[ -w test ]echo $?[ -x test ]echo $?按照文件类型进行判断-e文件存在existence)-f文件存在并且是一个常规的文件file-d文件存在并且是一个目录directory)[ -e test ]echo $?[ -f test ]echo $?[-d test ]echo $?a15[ $a -lt 20 ] echo $a 20 || echo $a 20输出15 20a27[ $a -lt 20 ] echo $a 20 || echo $a 20输出27 20if单分支cd /scriptsvim if_test.sh在条件判断里面加入双引号和x防止报错当变量传入为空时就用上x。#!/bin/bash if [ $1x happygamex ] then echo welcome, happygame fichmod x if_test.sh./if_test.sh happygamea25if [ $a -gt 18 ] [ $a -lt 35 ]; then echo OK; fi输出OKif多分支vim if_test.sh#!/bin/bash if [ $1x happygamex ] then echo welcome, happygame fi # 输入第二个参数表示年龄判断属于哪个年龄段 if [ $2 -lt 18 ] then echo 未成年人 else echo 成年人 fi./if_test.sh happygame 15未成年人./if_test.sh happygame 25成年人vim if_test.sh#!/bin/bash if [ $1x happygamex ] then echo welcome, happygame fi # 输入第二个参数表示年龄判断属于哪个年龄段 if [ $2 -lt 18 ] then echo 未成年人 elif [ $2 -lt 35 ] then echo 青年人 elif [ $2 -lt 60 ] then echo 中年人 else echo 老年人 fi./if_test.sh happygame 25青年人./if_test.sh happygame 45中年人./if_test.sh happygame 65老年人casevim case_test.sh#!/bin/bash case $1 in 1) echo one ;; 2) echo two ;; 3) echo three ;; *) echo number else ;; esacchmod x case_test.sh./case_test.sh 2two./case_test.sh 6number elseforvim sum_to.sh用$取到sum和i的值加号运算符要在$和[]运算表达式中#!/bin/bash for (( i1; i $1; i )) do sum$[ $sum $i ] done echo $sumchmod x sum_to.sh./sum_to.sh 100输出5050以下是linux中常用的写法for os in linux windows macos; do echo $os; done输出这三个操作系统名称for i in {1..100}; do sum$[$sum$i]; done; echo $sum输出5050$*和$的区别vim parameter_for_test.sh#!/bin/bash echo --------------$*------------- for para in $* do echo $para done echo --------------$------------- for para in $ do echo $para donechmod x parameter_for_test.sh./parameter_for_test.sh a b c d e$*把它们作为一个整体$仍然把他们作为独立个体。结果如下whilevim sum_to.sh#!/bin/bash # 用for实现 for (( i1; i $1; i )) do sum$[ $sum $i ] done echo $sum # 用while实现 a1 while [ $a -le $1 ] do sum2$[ $sum2 $a ] a$[$a 1] done echo $sum2./sum_to.sh 100输出两个5050read用于读取控制台输入。-p指定读取值时的提示。-t指定读取值时等待的时间(秒)如果不加 - t则一直等待。vim read_test.sh#!/bin/bash read -t 10 -p 请输入您的名字 name echo welcome, $namechmod x read_test.sh./read_test.sh系统函数vim cmd_test.sh$(date %s)相当于用$()将date函数的值取出来。#!/bin/bash filename$1_log_$(date %s) echo $filenamechmod x cmd_test.sh./cmd_test.sh happygamebasename /root/scripts/parameter.sh结果输出parameter.shbasename /root/scripts/parameter.sh .sh结果输出parameter删除了后缀.shvim parameter.sh#!/bin/bash echo ----------$n----------- echo script name: $(basename $0 .sh) echo 1st parameter:$1 echo 2nd parameter:$2 echo ----------$#----------- echo parameter numbers:$# echo ----------$*----------- echo $* echo ----------$----------- echo $/scripts/parameter.sh a bdirname /root/scripts/parameter.sh结果输出/root/scriptsvim parameter.sh先进入路径再得出绝对路径。#!/bin/bash echo ----------$n----------- echo script name: $(basename $0 .sh) echo script path: $(cd $(dirname $0); pwd) echo 1st parameter:$1 echo 2nd parameter:$2 echo ----------$#----------- echo parameter numbers:$# echo ----------$*----------- echo $* echo ----------$----------- echo $./parameter.sh a b自定义函数vim fun_test.sh用sum变量得到echo的返回值如果用$?返回只能返回0-255的数字。#!/bin/bash function add(){ s$[$1 $2] echo $s } read -p 请输入第一个整数: a read -p 请输入第二个整数: b sum$(add $a $b) echo 和: $sumchmod x fun_test.sh./fun_test.sh接下来要手动输入两个数还可以计算和的平方:#!/bin/bash function add(){ s$[$1 $2] echo $s } read -p 请输入第一个整数: a read -p 请输入第二个整数: b sum$(add $a $b) echo 和的平方: $[$sum * $sum]练习一归档文件vim daily_archive.sh#!/bin/bash # 首先判断输入参数个数是否为1 if [ $# -ne 1 ] then echo 参数个数错误应该输入一个参数作为归档的目录名。 exit fi # 从参数中获取目录名称 if [ -d $1 ] then echo else echo echo 目录不存在 echo exit fi DIR_NAME$(basename $1) DIR_PATH$(cd $(dirname $1); pwd) # 获取当前日期 DATE$(date %y%m%d) # 定义生成的归档文件名称 FILEarchive_${DIR_NAME}_$DATE.tar.gz DEST/root/archive/$FILE # 开始归档目录文件 echo 开始归档... echo tar -czf $DEST $DIR_PATH/$DIR_NAME # 判断是否归档成功 if [ $? -eq 0 ] then echo echo 归档成功 echo 归档文件为: $DEST echo else echo 归档出现问题! echo fi exitmkdir /root/archivechmod ux daily_archive.sh./daily_archive.sh ../scripts接下来将这个脚本加入到定时任务中crontab -e0 2 * * * /root/scripts/daily_archive.sh /root/scripts常用特殊字符cat /etc/passwd | grep ^a找到以a开头的内容cat /etc/passwd | grep bash$找到以bash结尾的内容cat daily_archive.sh | grep -n ^$找到空行的位置-n显示行号cat daily_archive.sh | grep r..t找到r和t中间有两个任意字符的内容如rootcat etc/passwd | grep ro*t找到o出现0次或多次的内容如rtrotroot等cat etc/passwd | grep ^a.*bash$找到以a开头以bash结尾的内容cat etc/passwd | grep ^a.*var.*in$找到以a开头以in结尾中间还有var的内容[6,8]匹配6或者 8[0-9]匹配一个0-9的数字[0-9]*匹配任意长度的数字字符串[a-z]匹配一个a-z之间的字符[a-z]*匹配任意长度的字母字符串[a-c,e-f]匹配a-c或者e-f之间的任意字符cat /etc/passwd | grep r[a,b,c]*t找到rtratrbtrabt等的内容cat daily_archive.sh | grep \$用\转义找到含$的内容echo 13812345678 | grep ^1[34578][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]$筛选手机号echo 13812345678 | grep -E ^1[34578][0-9]{9}$用-E支持扩展的正则cutvim cut.txtdong shen guan zhen wo wo lai lai le lecat cut.txt-f列号提取第几列-d分隔符按照指定分隔符分割列默认制表符\t-c按字符进行切割加n表示取第几列cut -d -f 1 cut.txt截取出第一列的内容cut -d -f 2,3 cut.txt截取第二、三列的内容cat /etc/passwd | grep bash$cat /etc/passwd | grep bash$ | cut -d : -f 1,6,7截取出以下内容cat /etc/passwd | grep bash$ | cut -d : -f 1-4截取1-4列cat /etc/passwd | grep bash$ | cut -d : -f -4截取1-4列cat /etc/passwd | grep bash$ | cut -d : -f 4-截取4到最后一列ifconfig ens33 | grep netmask | cut -d -f 10截取到IP地址inet前面有8个空格ifconfig | grep netmask | cut -d -f 10截取出IP地址本地环回地址虚拟地址awk-F指定输入文件分隔符空格为默认分隔符-v赋值一个用户定义变量cat /etc/passwd | grep ^root | cut -d : -f 7以root开头的第七列所有内容cat /etc/passwd | awk -F : /^root/ {print $7}等价于上面的式子cat /etc/passwd | awk -F : /^root/ {print $1,$7}第一列和第七列要给逗号打双引号拼接cat /etc/passwd | awk -F : /^root/ {print $1,$6,$7}第一列第六列和第七列cat /etc/passwd | awk -F : BEGIN{print user, shell}{print $1,$7} END{print end of file}在最开头加入user, shell在结尾加入end of filecat /etc/passwd | awk -F : {print $31}将第三列的数字全部加1cat /etc/passwd | awk -v i1 -F : {print $3i}将第三列的数字全部加i更灵活awk的内置变量FILENAME文件名NR已读的记录数行号NF浏览记录的域的个数切割后列的个数awk -F : {print 文件名FILENAME 行号NR 列数NF } /etc/passwd显示文件名、行号、列数ifconfig | awk /^$/ {print 空行NR}显示空行的行号ifconfig | awk /netmask/ {print $2}显示IP地址本地环回地址虚拟地址awk前八个空格不考虑练习二发送消息mesg查看是否打开消息功能who -T则打开了消息功能-则关闭了消息功能vim send_msg.sh#!/bin/bash # 查看用户是否登录(-i忽略大小写-m最多拿几行awk那第一列) login_user$(who | grep -i -m 1 $1 | awk {print $1}) # -z判断是否为空 if [ -z $login_user ] then echo $1 不在线 echo 脚本退出... exit fi # 查看用户是否开启消息功能 is_allowed$(who -T | grep -i -m 1 $1 | awk {print $2}) if [ $is_allowed ! ] then echo $1 没有开启消息功能 echo 脚本退出... exit fi # 确认是否有消息发送 if [ -z $2 ] then echo 没有消息发送 echo 脚本退出... exit fi # 从参数中获取要发送的消息 whole_msg$(echo $* | cut -d -f 2-) # 获取用户登录的终端 user_terminal$(who | grep -i -m 1 $1 | awk {print $2}) # 写入要发送的消息(write写入要指定发送的用户和发送的终端) echo $whole_msg | write $login_user $user_terminal if [ $? ! 0 ] then echo 发送失败 else echo 发送成功 fi exitchmod ux send_msg.sh./send_msg.sh happygame hi, happygame

更多文章