Linux命令-Shell编程

Shell是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核。

写一个hello.sh脚本:

1.mkdir scripts

2.cd scripts

3.touch hello.sh

4.vim hello.sh

bash 复制代码
#!/bin/bash
echo "hello,world"

5.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 | 查看系统变量 |
| env | less | 查看所有系统全局变量 |
| set | less | 查看定义的所有变量 |


自定义变量

在子shell更改变量,不影响父shell。
全局环境变量名字建议大写。

a=2(等号两边不能加空格)

echo $a

s="hello, world"(变量的值有空格,需要使用双引号括起来。)

echo $s

export s(升级成全局变量)

a=((1+5))(可以进行符号运算) a=[1+5]

echo $a

readonly b=5(定义一个只读变量)

b=10(报错,只读)

unset a(删除变量a)

unset b(删除不了,只读)


特殊变量

1.n (功能描述:n为数字,0代表该脚本名称,1-9代表第一到第九个参数,十以上的参数需要用大括号包含,如${10})

vim hello.sh

bash 复制代码
#!/bin/bash
echo "hello, world"
echo "hello, $1"

./hello.sh xiaoming(将xiaoming填入$1)

vim parameter.sh
单引号就不会把里面的$认为是变量,而是原封不动输出。

bash 复制代码
#!/bin/bash
echo '----------$n-----------'
echo script name:$0
echo 1st parameter:$1
echo 2nd parameter:$2

chmod +x parameter.sh

./parameter.sh abc def

2.$#(功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确以及加强脚本的健壮性)。

vim parameter.sh

bash 复制代码
#!/bin/bash
echo '----------$n-----------'
echo script name:$0
echo 1st parameter:$1
echo 2nd parameter:$2
echo '----------$#-----------'
echo parameter numbers:$#

./parameter.sh abc def

3.\*(功能描述:这个变量代表命令行中所有的参数,*把所有的参数看成一个整体)
@(功能描述:这个变量也代表命令行中所有的参数,不过@把每个参数区分对待)

vim parameter.sh

bash 复制代码
#!/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 def

4.$?(功能描述:最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行:如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确了。)

echo $?(接上面代码,结果为0)

parameter.sh(报错)

echo $?(非0)


运算符

echo $[5 * 2]

s=$[(2+3) * 4]

echo $s

cd /scripts

vim add.sh

bash 复制代码
#!/bin/bash
sum=$[$1 + $2]
echo sum=$sum

chmod +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 $?

a=15

$a -lt 20 \] \&\& echo "$a \< 20" \|\| echo "$a \> 20"(输出15 \< 20) a=27 \[ $a -lt 20 \] \&\& echo "$a \< 20" \|\| echo "$a \> 20"(输出27 \> 20) *** ** * ** *** ### **if单分支** cd /scripts vim if_test.sh **在条件判断里面加入双引号和x防止报错,当变量传入为空时就用上x。** ```bash #!/bin/bash if [ "$1"x = "happygame"x ] then echo "welcome, happygame" fi ``` chmod +x if_test.sh ./if_test.sh happygame a=25 if \[ $a -gt 18 \] \&\& \[ $a -lt 35 \]; then echo OK; fi(输出OK) *** ** * ** *** ### **if多分支** vim if_test.sh ```bash #!/bin/bash if [ "$1"x = "happygame"x ] 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 ```bash #!/bin/bash if [ "$1"x = "happygame"x ] 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(老年人) *** ** * ** *** ### **case** vim case_test.sh ```bash #!/bin/bash case $1 in 1) echo "one" ;; 2) echo "two" ;; 3) echo "three" ;; *) echo "number else" ;; esac ``` chmod +x case_test.sh ./case_test.sh 2(two) ./case_test.sh 6(number else) *** ** * ** *** ### **for** vim sum_to.sh **用$取到sum和i的值,加号运算符要在$和\[\]运算表达式中** ```bash #!/bin/bash for (( i=1; i <= $1; i++ )) do sum=$[ $sum + $i ] done echo $sum ``` chmod +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 ```bash #!/bin/bash echo '--------------$*-------------' for para in "$*" do echo $para done echo '--------------$@-------------' for para in "$@" do echo $para done ``` chmod +x parameter_for_test.sh ./parameter_for_test.sh a b c d e **$\*把它们作为一个整体,$@仍然把他们作为独立个体。** 结果如下: ![](https://i-blog.csdnimg.cn/direct/8c8be048d745432b9c504046981d3828.png) *** ** * ** *** ### **while** vim sum_to.sh ```bash #!/bin/bash # 用for实现 for (( i=1; i <= $1; i++ )) do sum=$[ $sum + $i ] done echo $sum # 用while实现 a=1 while [ $a -le $1 ] do sum2=$[ $sum2 + $a ] $a=$[$a + 1] done echo $sum2 ``` ./sum_to.sh 100(输出两个5050) *** ** * ** *** ### read **用于读取控制台输入。** |----|------------------------------| | -p | 指定读取值时的提示。 | | -t | 指定读取值时等待的时间(秒)如果不加 - t则一直等待。 | vim read_test.sh ```bash #!/bin/bash read -t 10 -p "请输入您的名字:" name echo "welcome, $name" ``` chmod +x read_test.sh ./read_test.sh *** ** * ** *** ### 系统函数 vim cmd_test.sh **$(date +%s)相当于用$()将date函数的值取出来。** ```bash #!/bin/bash filename="$1"_log_$(date +%s) echo $filename ``` chmod +x cmd_test.sh ./cmd_test.sh happygame basename /root/scripts/parameter.sh(结果输出parameter.sh) basename /root/scripts/parameter.sh .sh(结果输出parameter,删除了后缀.sh) vim parameter.sh ```bash #!/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 $@ ``` /root/scripts/parameter.sh a b dirname /root/scripts/parameter.sh(结果输出/root/scripts) vim parameter.sh **先进入路径,再得出绝对路径。** ```bash #!/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的数字。** ```bash #!/bin/bash function add(){ s=$[$1 + $2] echo $s } read -p "请输入第一个整数: " a read -p "请输入第二个整数: " b sum=$(add $a $b) echo "和: "$sum ``` chmod +x fun_test.sh ./fun_test.sh(接下来要手动输入两个数) **还可以计算和的平方:** ```bash #!/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 ```bash #!/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) # 定义生成的归档文件名称 FILE=archive_${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 exit ``` mkdir /root/archive chmod u+x daily_archive.sh ./daily_archive.sh ../scripts **接下来将这个脚本加入到定时任务中:** crontab -e ```bash 0 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中间有两个任意字符的内容,如root | | cat etc/passwd \| grep ro\*t | 找到o出现0次或多次的内容,如rt,rot,root等 | | 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 | 找到rt,rat,rbt,rabt等的内容 | | 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支持扩展的正则 | *** ** * ** *** ### cut vim cut.txt ```bash dong shen guan zhen wo wo lai lai le le ``` cat 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$ ![](https://i-blog.csdnimg.cn/direct/0795c1c5630f4766a21c21d5f94a38ba.png) cat /etc/passwd \| grep bash$ \| cut -d ":" -f 1,6,7 **截取出以下内容:** ![](https://i-blog.csdnimg.cn/direct/f85f1aec74f149c6a6999f86a4eb93ca.png) |----------------------------------------------------|---------------------| | 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 file | |-----------------------------------------------------|-----------------| | cat /etc/passwd \| awk -F ":" '{print $3+1}' | 将第三列的数字全部加1 | | cat /etc/passwd \| awk -v i=1 -F ":" '{print $3+i}' | 将第三列的数字全部加i,更灵活 | |----------|--------------------| | FILENAME | 文件名 | | NR | 已读的记录数(行号) | | NF | 浏览记录的域的个数(切割后列的个数) | [awk的内置变量] |--------------------------------------------------------------------|--------------------------------| | awk -F ":" '{print "文件名:"FILENAME " 行号:"NR " 列数:"NF }' /etc/passwd | 显示文件名、行号、列数 | | ifconfig \| awk '/\^$/ {print "空行:"NR}' | 显示空行的行号 | | ifconfig \| awk '/netmask/ {print $2}' | 显示IP地址,本地环回地址,虚拟地址,awk前八个空格不考虑 | *** ** * ** *** ### 练习二:发送消息 mesg(查看是否打开消息功能) who -T(+则打开了消息功能,-则关闭了消息功能) ![](https://i-blog.csdnimg.cn/direct/386ed2fbb0a246e5adc4743b35d0dafa.png) vim send_msg.sh ```bash #!/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 exit ``` chmod u+x send_msg.sh ./send_msg.sh happygame hi, happygame

相关推荐
YPrefY31 分钟前
HADOOP 3.4.1安装和搭建(尚硅谷版~)
大数据·linux·hadoop
liuluyang53035 分钟前
linux 4.14内核jffs2文件系统不自动释放空间的bug
linux·elasticsearch·bug·jffs2
易保山38 分钟前
MIT6.S081 - Lab9 File Systems(文件系统)
linux·操作系统·c
林开落L43 分钟前
Linux深度探索:进程管理与系统架构
linux·运维·系统架构
林政硕(Cohen0415)1 小时前
在ARM Linux应用层下驱动MFRC522
linux·mfrc522·ic-s50·m1卡
艾伦_耶格宇2 小时前
shell 脚本实验 -5 while循环
linux
独隅2 小时前
PyCharm 在 Linux 上的完整安装与使用指南
linux·ide·pycharm
想躺在地上晒成地瓜干2 小时前
树莓派超全系列教程文档--(38)config.txt视频配置
linux·音视频·树莓派·raspberrypi·树莓派教程
自由如风7092 小时前
Apache Atlas构建安装(Linux)
linux·运维·apache
烦躁的大鼻嘎2 小时前
【Linux】进程替换与自定义 Shell:原理与实战
linux·运维·服务器·ubuntu