第8章:shell编程:bash特殊符号、常用快捷键、输入输出重定向;变量、字符串操作、数组;read命令;shell运算符let/expr/bc/$(())/$[];流程控制if/case/for/while/until/select/trap

shell脚本格式;调试shell脚本;()与{}的区别;bash退出状态 ============================================================= shell脚本基础 格式要求:首行shebang机制 #!/bin/bash #!/usr/bin/python #号是shexxx,!是bang 注释以#开头 ---------------------------------------------------------------------------------------------- 运行脚本的方式: 1.给予脚本执行权限,在命令行上以绝对路径运行脚本 2.给予脚本执行权限,在命令行上以相对路径运行脚本(此处相对路径是./xxx的形式) 3.类似命令的方式来运行脚本,将脚本文件放在$PATH中的目录下,建议放在家目录的bin目录下,例如root用户的~/bin 4.使用解释器运行脚本,例如 bash aaa.sh;python bbb.py 5. [root@yefeng28325 ~]# echo "echo hello world" |bash [root@yefeng28325 ~]# cat hello.sh |bash [root@yefeng28325 ~]# curl http://192.168.0.1/hello.sh |bash 脚本调试 bash -n systeminfo.sh #检查脚本的语法错误 bash -n /root/bin/systeminfo.sh #检查脚本的语法错误 bash -x systeminfo.sh #调试执行 bash -x /root/bin/systeminfo.sh #调试执行 --------------------------------------------------------------------------------------------- 语法错误才会导致程序终止;非语法错误不影响后续的执行 脚本规范 #!/bin/bash 第一个一般为调用使用的语言 ######################################################################### # File Name: test.sh 程序名,避免更改文件名而无法找到正确的文件 # Revision: 1.1 版本号 # Date: 2020/06/01 最后更改时间 # Author: yefeng 作者 # mail: 10086@qq.com # Description: xxxxxxx 功能描述,注意事项 ######################################################################### # xxxxxxx: xxxxxxx 各个版本的更新简要说明 ---------------------------------------------------------- ()与{}的区别 1.()小括号内的命令是运行在子shell进程中的;{}大括号则是在当前进程中运行的 在man bash中可以查找相关说明,”/\(list\)”查找小括号的说明;”/\{ list; \}”查找大括号的说明 小括号启用的子进程是可以拿到当前进程的局部变量;这一点和一般的子进程不一样!(比如通过bash开启一个子进程) ---------------------------------------------------------- 退出状态 进程使用退出状态来报告成功or失败 0表示成功,1-255表示失败 变量$?保存了最近一个命令的退出状态(查看了菜鸟教程,$?也会保存函数的返回值嘛,即函数return的内容) bash中自定义退出状态码:exit [n] 注意:脚本中一旦遇到exit命令,脚本会立即终止;退出状态取决于exit命令后面的数字 注意2:如果未给脚本指定退出状态码,那么退出状态码默认为脚本中执行的最后一条命令的状态码

shell中特殊符号'' "" `` $() () {} [ ] # $ \ '' 单引号。在单引号中所有的特殊符号,如“$”和”(反引号)都没有特殊含义。单引号括起来的都是普通字符,会原样输出 "" 双引号。在双引号中特殊符号都没有特殊含义,但是“$”,"`"(esc键下面)和“\”是例外,拥有“调用变量的值”、“引用命令”和“转义符”的特殊含义。 `` 反引号。反引号括起来的内容是系统命令,在Bash中会先执行它。和( ) 作 用 一 样 , 不 过 推 荐 使 用 ()作用一样,不过推荐使用()作用一样,不过推荐使用(),因为反引号非常容易看错。 $() 和反引号作用一样,用来引用系统命令。(推荐使用) () 用于一串命令执行时,()中的命令会在子Shell中运行 {} 用于一串命令执行时,{ }中的命令会在当前Shell中执行。也可以用于变量变形与替换。 [ ] 用于变量的测试。 # 在Shell脚本中,#开头的行代表注释。 $ 用于调用变量的值,如需要调用变量name的值时,需要用$name的方式得到变量的值。 \ 转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。如$将输出“$”符号,而不当做是变量引用。

小知识点 ======================================= [root@yefeng28325 ~]# name="echo" [root@yefeng28325 ~]# $name "echo2" echo2 [root@yefeng28325 ~]# echo $name 这两者的差异需要细细体会 echo [[]]双层中括号的说明可以在man bash中找到,/\[\[ 使用== != 匹配的是通配符 而=~时,匹配的却是扩展正则 别名默认是不能放在脚本里运行的,即脚本里的alias是无效的
Bash 常用快捷键---第1章:linux基础
输入输出重定向---第1章:linux基础
变量

用户环境变量文件/etc/profile、/etc/profile.d/*.sh、/etc/bashrc、~/.bash_profile,~/.bashrc;shell的两种登陆方式;bash退出任务 ~/.bash_logout文件;变量$- --------------------------------------------------------------------------------- 配置用户环境 bash的配置文件 按影响范围分类 1.全局配置:/etc/profile,/etc/profile.d/*.sh,/etc/bashrc 2.个人配置:~/.bash_profile,~/.bashrc (bashrc bash run command) 按功能分类: 1.profile类:/etc/profile,/etc/profile.d/*.sh,~/.bash_profile (1)用户定义环境变量;(2)运行命令or脚本 2.bashrc类:/etc/bashrc,~/.bashrc (1)定义别名and函数;(2)定义本地变量 全局环境变量建议存放在/etc/profile.d/*.sh 个人环境变量建议存放在~/.bash_profile 全局别名and函数建议放在/etc/bashrc 个人别名and函数建议放在~/.bashrc 修改profile和bashrc文件后,生效的两种方法: 1.重启shell进程 2.source或. 重新加载文件 source是在当前shell进程运行,而不是开启一个子进程运行脚本,所以source可以重新加载配置 反过来,我们一般不用source去运行脚本,因为可能会导致环境变量被修改! --------------------------------------------------------------------------------- shell两种登陆方式(加载配置的顺序和种类都不同) 1.交互式登陆 (1)直接通过终端输入密码登陆 (2)su - 切换用户 执行配置顺序:/etc/profile--->/etc/profile.d/*.sh--->~/.bash_profile--->~/.bashrc--->/etc/bashrc 2.非交互式登陆 (1)su 切换用户(不携带"-") (2)图形界面打开的终端 (3)执行脚本 (4)任何其他的bash实例 执行配置顺序:~/.bashrc--->/etc/bashrc--->/etc/profile.d/*.sh --------------------------------------------------------------------------------- bash退出任务 ~/.bash_logout文件:在退出登录shell是运行 1.创建自动备份 2.清除临时文件 --------------------------------------------------------------------------------- 变量$- [root@yefeng28325 ~]# echo $- himBH h:hashall,打开这个选项后,shell会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭 i:interactive-comments,包含这个选项说明当前的shell是一个交互式的shell;非交互登陆时,i选项是关闭的,例如脚本中 m:monitor,打开监控模式,就可以通过job control来控制进程的停止、继续,后台or前台执行等 B:braceexpand,大括号扩展 H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如"!!"最近的一个历史命令,"!n"第n个历史命令

profile、bashrc调用顺序的研究 [root@yefeng28325 ~]# cat /etc/profile # /etc/profile …………………………………………………… for i in /etc/profile.d/*.sh /etc/profile.d/sh.local ; do #在/etc/profile快结束时,就去调用/etc/profile.d/*.sh了 if [ -r "$i" ]; then if [ "${-#*i}" != "$-" ]; then . "$i" else . "$i" >/dev/null fi fi done unset i unset -f pathmunge ==================================================================== [root@yefeng28325 ~]# cat .bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then #在运行.bash_profile时,会去调用~/.bashrc . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin export PATH [root@yefeng28325 ~]# ==================================================================== [root@yefeng28325 ~]# cat .bashrc # .bashrc # User specific aliases and functions alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # Source global definitions if [ -f /etc/bashrc ]; then #在运行~/.bashrc时,会去调用/etc/bashrc . /etc/bashrc fi ==================================================================== [root@yefeng28325 ~]# cat /etc/bashrc #这个是最后执行的

变量;局部变量;环境变量;只读变量和位置变量;变量引用 ================================================= 变量 bash的变量是弱类型;java,c#等语言的变量为强类型 弱类型变量:语言在运行时会隐式做数据类型转换;无需指定类型,默认为字符型;参与运算会自动进行隐式类型转换;变量无需事先定义可直接调用。 强类型变量:使用变量必须先声明变量,且指定变量类型;不允许隐式的类型转换;参与运算必须符合类型要求;可以进行强制类型转换。 变量命名法则: 1.不能使用系统保留的关键字,例如if、for 2.只能使用属组、字母、下划线,且不能以数字开头 3.见名知义 4.建议使用驼峰命名法(命名法可以参考各种系统文件or模块;java类名使用大驼峰,方法使用小驼峰;python则建议使用下划线) bash中的变量 根据变量的生效范围划分 1.局部变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效 2.环境变量(全局变量):生效范围为全局 3.本地变量:生效范围为当前shell进程中某代码片段,通常指函数 4.位置变量:$1,$2...(注意$(10)),运行脚本时传递的参数 5.特殊变量:$?,$0,$*,$@,$#,$$ $$:当前进程的进程ID $PPID:当前进程的的父进程ID ---------------------------------------------------------- 局部变量 变量赋值: name='value' #将字符串赋值给变量(注意:赋值时,=号前后无空格) name1=$name #将某变量的值赋值给变量 name2=`COMMAND` name3=$(COMMAND) #将命令的结果赋值给变量 ---------------------------------------------------------- 环境变量 环境变量声明、赋值: export name=value declare -x name=value 显示所有环境变量: env;printenv;export;declare -x; #可能存在些许不同 bash内建的环境变量: PATH SHELL USER UID HOME PWD SHLVL #嵌套深度 LANG MAIL HOSTNAME HISTSIZE _ 下划线 - 环境变量大多数在/etc/profile文件中初始化,该文件在用户登录时候执行 所有的shell环境变量都会被传递给shell的子程序 $HOME 读写 当前用户的主目录 $PATH 读写 以冒号分割的,用来搜索命令的目录列表 $PS1 读写 命令提示符,通常是$符号,但在bash中,你可以使用一些更复杂的值。 $PS2 读写 二级提示符,用来提示后续的输入,通常是>字符 $IFS 读写 输入域分隔符当shell读取输入时,用来分隔单词的一组字符,他们通常是空格、制表符和换行符 $0 只读 shell脚本的文件名字 $1-9 只读 命令行参数1-9的值,参数10之后建议使用${10}这种形式 $* 只读 这个变量代表命令行中所有的参数,$把所有的参数看成一个整体 $@ 只读 这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待 实测:当$@与$*都用""包括时,即"$*"、"$@";"$*"是字符串,"$@"是数组 $# 只读 命令行参数的总个数 $$ 只读 shell脚本进程的ID号 $? 只读 最近一次命令的退出状态 $! 只读 最近一次后台进程的ID号 ---------------------------------------------------------- 只读变量和位置变量 声明只读变量: readonly name declare -r name 查看只读变量: readonly -p 位置变量:在运行脚本时,传递给脚本的参数 $1,$2...$(10);对应第1、第2、第10个参数,shift[n]换位置 $0 命令本身,即脚本名称 $* 传递给脚本的所有参数,全部参数合为一个字符串 $@ 传递给脚本的所有参数,每个参数为独立字符串 $*$@ 只有在双引号包起来的时候才会有差异 $# 传递给脚本的参数个数 set -- #清空所有位置变量 shift 移除指定个数的位置变量,默认移除第一个变量 用法:shift;shift 2 ---------------------------------------------------------- 变量引用 ${name} $name #引用变量时建议使用"$"符号;"$"不是必须的,只要命令可以识别出变量,那么就可以不加"$"(这个需要经验的积累,才知道哪些命令可以不需要加"$") "" #弱引用,bash将会解析""中的变量(在双引号中的变量仍然是需要加"$"的) '' #强引用,所见即所得 显示已定义的所有变量:set 删除变量:unset name

变量相关命令的比较:declare、unset、set、env、export、readonly
==============================================================================
变量相关命令的比较:declare、unset、set、env、export、readonly
declare命令用于声明和显示已存在的shell变量。当不提供变量名参数时显示所有shell变量。declare命令若不带任何参数选项,则会显示所有shell变量及其值。declare的功能与typeset命令的功能是相同的。
unset命令用于删除已定义的shell变量(包括环境变量)和shell函数。unset命令不能够删除具有只读属性的shell变量和环境变量。
set命令作用主要是显示系统中已经存在的shell变量,以及设置shell变量的新变量值。使用set更改shell特性时,符号"+"和"-"的作用分别是打开和关闭指定的模式。set命令不能够定义新的shell变量。如果要定义新的变量,可以使用declare命令
env命令用于显示系统中已存在的环境变量,以及在定义的环境中执行指令。该命令只使用"-"作为参数选项时,隐藏了选项"-i"的功能。若没有设置任何选项和参数时,则直接显示当前的环境变量。
set命令可以查看所有变量,而env命令只能查看环境变量。
export命令用于将shell变量输出为环境变量,或者将shell函数输出为环境变量。
readonly命令用于定义只读shell变量和shell函数。readonly命令的选项-p可以输出显示系统中所有定义的只读变量。
https://www.cnblogs.com/qlqwjy/p/9075766.html
总结:
1.declare var=value 可以声明一个shell变量(与之等价的是 var=value,typeset var=value),也可以直接用declare -x var=value 声明一个变量并直接输出到环境变量,也可以加上-r参数表示只读变量。
2.unset var 可以删除变量,包括shell变量和环境变量(当前用户变量),不能够删除具有只读属性的shell变量和环境变量。
3.set -a var 可以将var变量输出到环境变量
4.env可以查看所有的环境变量,可以加管道命令与grep命令过滤变量
5.export var=value用于定义一个环境变量,修改环境变量也是这个,等价于 declare -x var=name
export -n var 用于从环境变量删除此变量,但是shell变量中此变量仍然存在。

变量赋值操作;字符串切片、处理 ========================================================================= 变量赋值操作 变量配置方式 var未初始化 var为空字符串 var为非空字符串 $variable 空 $variable $variable ${variable} 空 $variable $variable ${variable-string} string 空 $variable ${variable:-string} string string $variable ${variable+string} 空 string string ${variable:+string} 空 空 string ${variable=string} 功能同"-",区别在于当var未初始化未初始化时,variable会被初始化为string ${variable:=string} 功能同":-",区别在于当var未初始化未初始化or var为空时,variable会被初始化为string ${variable?string} expr输出到stderr 空 $variable ${variable:?string} expr输出到stderr expr输出到stderr $variable ======================================================================== 字符串切片、处理 ${#var} #返回var的长度 ${#var:offset} #字符串切片,取自偏移量offset到结束的所有字符 ${#var:offset:number} #字符串切片,取自偏移量offset之后的number个数字符 ${#var: -length} #字符串切片,注意有空格,去倒数的指定length位数到结尾的字符 ${#var: -length:offset} #字符串切片,注意有空格,去倒数的指定length位数字符,然后再指定偏移量offset 字符串处理 本质上#%这2个符号才是模式的关键,*只是用来进行匹配的。。。 ${var#*word} #使用word在字符串var中从左向右进行匹配;若未匹配,则显示字符串var;若有匹配,则只显示匹配后的所有字符 ${var##*word} #功能基本同上,但该模式为贪婪模式;即上面的方式,只会进行一次匹配;而这种方式则会进行多次匹配,以最后一次匹配为准 ${var%word*} #从右向左匹配,功能同上 ${var%%word*} #从右向左匹配,贪婪模式 查找并替换 ${var/word1/word2} #查找word1,替换为word2;仅替换第一个匹配到的 ${var//word1/word2} #查找替换,替换所有 ${var/#word1/word2} #仅匹配行首 ${var/%word1/word2} #仅匹配行尾 查找并删除 ${var/word1} #查找并删除,其实就是查找替换的缩减版本 ${var//word1} ${var/#word1} ${var/%word1} 字符串转换大小写 ${var^^} #所有字母大写 ${var,,} #所有字符小写

declare、typeset;删除变量unset;set命令 =================================================== https://www.cnblogs.com/klb561/p/9236468.html typeset现在已经基本不用了,就用declare declare也可以申明环境变量,只是用export更多而已 declare命令(别名typeset)属shell内建命令,用于申明shell变量并设置变量属性,或查看已定义的shell变量和函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。 declare命令用于声明 shell 变量 +/- "-"可用来指定变量的属性,"+"则是取消变量所设的属性。 -i 设置变量为整数,[设置值]可以是数值,字符串或运算式。 -a 设置变量为数组array -r 设置变量为只读 -f 如果后面没有参数的话会列出之前脚本定义的所有函数,如果有参数的话列出以参数命名的函数 -x 指定的变量会成为环境变量,可供shell以外的程序来使用。 -a:申明数组变量 -A:申明关联数组,可以使用字符串作为数组索引 -f:仅显示已定义的函数 -F:不显示函数定义 -i:声明整型变量 -l:将变量值的小写字母变为小写 -u:变量值的大写字母变为大写 -r:设置只读属性 -t:设置变量跟踪属性,用于跟踪函数进行调试,对于变量没有特殊意义 -x:将指定的shell变量换成环境变量 -p:显示变量定义的方式和值 +:取消变量属性,但是+a和+r无效,无法删除数组和只读属性,可以使用unset删除数组,但是unset不能删除只读变量 第一种语法中可用来声明变量并设置变量的属性([rix]即为变量的属性), 第二种语法中可用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行set指令的效果相同)。 declare -x #查看所有环境变量 declare -x PATHXXX=112233 #声明环境变量 declare -i AA #声明整数型变量;当AA赋值为数字时,AA的值相应的数字;当AA赋值为字符串时,AA的值为0 declare +i AA #取消变量属性;此时AA可以被赋值为字符串了 declare -r #查看所有只读变量 declare -r ab #设置变量为只读 declare -a cd='([0]="a" [1]="b" [2]="c")' #声明数组变量;echo ${cd[1]};echo ${cd[@]} //显示整个数组变量内容 ------------------------------------------------------- 删除变量 可以使用unset命令,或者显式地将值置为null也可(null是所有未声明的变量的状态) unset为shell内建指令,可删除变量或函数。 -f 仅删除函数。 -v 仅删除变量。 unset 变量名 ------------------------------------------------------- set指令能设置所使用shell的执行方式,可依照不同的需求来做设置。 -v 显示shell所读取的输入值。 +参数 取消某个set曾启动的参数。

间接变量引用 如果第一个变量的值是第二个变量的名字,那么从第一个变量直接引用第二个变量的值成为间接变量应用 即var1的值为“var2”;“var2”既为“var1”的值,同时又为变量名 bash shell提供了两种格式实现间接变量引用 1.${!var1} 2.eval var3=\$$var1;echo $var3

数组 ================================================================ 数组:存储多个元素的连续的内存空间,相当于多个变量的集合 数组名和索引 索引:编号从0开始,属于数值索引 注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本才开始支持该特性 bash的属组支持稀疏格式(索引不连续) 声明数组 declare -a ARRAY_NAME declare -A ARRAY_NAME(关联数组) 关联属组,即属组的索引不是0123..;而是自定义的格式,例如0/a/b/6/7/8这种不规则的 注意:两者不可相互切换 ================================================================ 数组赋值 1.一次赋值一个元素 ARRAY_NAME[INDEX]=VALUE 示例:weekdays[0]="sunady" 2.一次性赋值所有元素 ARRAY_NAME=("VAL1" "VAL2" "VAL3") 3.只赋值特定元素 ARRAY_NAME=([0]="VAL1" [3]"VAL3") 4.交互式数组值对赋值 read -a ARRAY 显示所有数组:declare -a ================================================================ 引用数组 1.引用数组元素 ${ARRAY_NAME[INDEX]} 注意:[INDEX]可省略,省略即引用下标为0的元素 2.引用数组所有元素 ${ARRAY_NAME[*]} ${ARRAY_NAME[@]} 3.数组的长度 ${#ARRAY_NAME[*]} ${#ARRAY_NAME[@]} 4.删除数组中的某元素:导致稀疏格式 unset ARRAY_NAME[INDEX] 5.删除整个数组 unset ARRAY_NAME 使用实例 貌似也不需要显示地声明一个属组,可以直接对一个数组进行赋值的。。 但是关联数组一定要先声明 array1=(`ls`) array2=( /boot/* ) number=({1..10}) ================================================================ 数组数据处理 引用数组中的元素 数组切片:${ARRAY[@]:offset:number} offset:要跳过的元素个数 number:要去除的元素个数 去偏移量之后的所有元素${ARRAY[@]:offset} 向属组中追加元素: ARRAY[${#ARRAY[*]}]=value 关联数组: declare -A ARRAY_NAME ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2' [idx_name3]='val3') 注意:关联数组必须先声明再调用
shell变量默认是字符串型
命令替换、用户输入read

命令替换:$(command)或`command`这两种表达式,shell会执行该命令,并替换为该命令的输出。 ==================================================================== 用户输入read 选项: -a 后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符。 -p: “提示信息”:在等待read输入时,输出提示信息 -t: 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间 -n: 数字:read命令只接受指定的字符数,就会执行 -s: 隐藏输入的数据,适用于机密信息的输入 -d: 后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。 -e: 在输入的时候可以使用命令补全功能。 变量名: 变量名可以自定义,如果不指定变量名,会把输入保存入默认变量REPLY. 如果只提供了一个变量名,则整个输入行赋予该变量. 如果提供了一个以上的变量名,则输入行分为若干字,一个接一个地赋予各个变量,而命令行上的最后一个变量取得剩余的所有字 用法示例: read -p "输入网站名:" website echo "你输入的网站名是 $website" read #默认保存到默认变量REPLY
shell 运算符

算数运算符;bash中的6种数学运算:let命令、expr命令、bc命令、$(())、$[];逻辑运算 ============================================================================ 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。 expr 是一款表达式计算工具,使用它能完成表达式的求值操作。 运算符 说明 举例 + 加法 expr $a + $b 结果为 30。 - 减法 expr $a - $b 结果为 -10。 * 乘法 expr $a \* $b 结果为 200。 / 除法 expr $b / $a 结果为 2。 % 取余 expr $b % $a 结果为 0。 = 赋值 a=$b 将把变量 b 的值赋给 a。 == 相等。用于比较两个数字,相同则返回 true(真)。 [ $a == $b ] 返回 false(假)。 != 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。 **(乘方) 其他算术运算符: += -= *= /= %= ++ -- ---------------------------------------------------------- 实现算术运算 1.let var=算术表达式 2.var=$[算术表达式] 3.var=$((算术表达式)) 4.var=$(expr arg1 arg2 arg3 ...) 5.declare -i var=数值;var+=1 6.echo '算术表达式' |bc 注意:乘法符号在某些场景中需要转义,如* bash内建的随机数生成器:$RANDOM(0-32767) echo $[$RANDOM%50] 0-49之间的随机数 bash中的4种数学运算:let命令、expr命令、bc命令 let命令:let num+=10 用expr做计算的时候,运算符要与变量或数值间要有空格分开。 bc支持数学运算:echo 512*63*2610*255|bc ---------------------------------------------------------- 逻辑运算 ! 非 & and | or && 短路与(第一条命令判断结果为假,则跳过第二条命令的执行) || 短路或(第一条命令判断结果为真,则跳过第二条命令的执行) 短路判断其实就是判断第一个命名的执行结果,即判断$? ^ 异或(我的理解:异或是基于二进制进行判断的,任意字符串在进行异或时,先转变为二进制;然后进行同位比较;相同为假,不同为真,即0^0=0,1^1=0,1^0=1,0^1=1) 例如echo $((1^8))的结果为9;1转为二进制0001,8转为二进制1000,同位异或结果为1001,即9 echo $a $b;a=$((a^b));b=$((a^b));a=$((a^b));echo $a $b #实现数值交换 5 7 7 5

test 和 [ 命令、关系运算符、逻辑运算符、字符串运算符、文件测试运算符(重点) ============================================================================================================== 虽然 Linux 和 UNIX 的每个版本中都包含 test 命令,但该命令有一个更常用的别名 — 左方括号:[。test 及其别名通常都可以在 /usr/bin 或 /bin (取决于操作系统版本和供应商)中找到。 当您使用左方括号而非 test 时,其后必须始终跟着一个空格、要评估的条件、一个空格和右方括号。右方括号不是任何东西的别名,而是表示所需评估参数的结束。条件两边的空格是必需的,这表示要调用 test,以区别于同样经常使用方括号的字符/模式匹配操作。 ============================================================================================================== 关系运算符 运算符 单词 说明 举例 -eq equal 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。 -ne not equal 检测两个数是否相等,不相等返回 true。 [ $a -ne $b ] 返回 true。 -gt great than 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。 -lt less than 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。 -ge great than or equal 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。 -le less than or equal 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。 ---------------------------------------------------------------------------------------------------------- 逻辑运算符 运算符 说明 举例 ! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。 -o 或(或者)运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回 true。 -a 与(并且)运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。 ---------------------------------------------------------------------------------------------------------- 字符串运算符 运算符 说明 举例 = 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。 != 检测两个字符串是否相等,不相等返回 true。 [ $a != $b ] 返回 true。 -z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。 -n 检测字符串长度是否为0,不为0返回 true。 [ -n $a ] 返回 true。 str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。 ---------------------------------------------------------------------------------------------------------- 文件测试运算符(重点) 操作符 说明 举例 -b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。 -c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。 -d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。 -f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。 -g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。 -k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。 -p file 检测文件是否是有名管道,如果是,则返回 true。 [ -p $file ] 返回 false。 -u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。 -r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。 -w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。 -x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。 -s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。 -e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。 注意:权限几个判断,如果只有一个部分符合,则认为是有权限的。

条件测试test,[];条件性的执行操作符;bash的组合测试条件 ---------------------------------------------------------- 条件测试:若真,则返回0;若假,则返回1(bash真假的值与python相反) 测试命令:(注意:EXPRESSION前后必须有空白字符,判断结果是保存在$?中的!;中括号等效于test,查看帮助可以help test,man test) 1.test EXPRESSION 2.[ EXPRESSION ] #一般建议使用[],结构看起来更清晰 3.[[ EXPRESSION ]] #双层中括号内能识别扩展正则,一般使用“=~”时使用双层中括号 例如`[ 111 = 111 ]`;echo $? 建议"="两端的变量用双引号引起来;若变量为空,将会导致等式不成立,包语法错误 test命令(test等效于[])用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。 判断文件类型、文件权限、文件特殊权限: -a;-b;-d;-h;-r;-w;-x;-u;-g等等 例如:[ -a /root/bin/test.txt ] ;echo $? 数值比较: -eq 等于则为真 -ne 不等于则为真 -gt 大于则为真 -ge 大于等于则为真 -lt 小于则为真 -le 小于等于则为真 字符串比较(字符串测试): = 是否等于 > 是否大于,ascii码比较 < 是否小于,ascii码比较 != 是否不等于 =~ 左侧字符串是否能被右侧的PATTERN所匹配,即“=~”左侧为被匹配字符串,“=~”右侧为扩展正则表达式 详细情况help test,man test;注意:用于字符串比较时用到的操作数都应该使用引号 ---------------------------------------------------------- 条件性的执行操作符 根据退出状态而定,命令可以有条件地运行 EXPRESSION && COMMAND #条件为真,则执行命令 EXPRESSION || COMMAND #条件为假,则执行命令 拓展 EXPRESSION && COMMAND1 || COMMAND2 #条件为真,执行命令1;条件为假,执行命令2 EXPRESSION || COMMAND1 && COMMAND2 #与上相反 EXPRESSION && COMMAND1 && COMMAND2 #条件为真,执行命令1、命令2 ---------------------------------------------------------- bash的组合测试条件 方式1: COMMAND1 && COMMAND2 COMMAND1 || COMMAND2 ! COMMAND 方式2: EXPRESSION1 -a EXPRESSION2 #在test中-a有两种用法:1.用于判断文件是否存在;2.用于判断,效果等同于&& EXPRESSION1 -o EXPRESSION2 #同上 ! EXPRESSION
[[ $n =~ ^[:digit:]+$ ]] #判断是否为数字
流程控制

if条件判断 ====================================================== if 条件1;then 代码1; elif 条件2;then 代码2;else 代码3;fi #if语句可以写在一行,但是建议分行,结构更清晰 ------------------------- if [ 条件判断式1 ] #if使用分行书写时,';'可以不写! then 当条件判断式1成立时,执行程序1 elif [ 条件判断式2 ] then 当条件判断式2成立时,执行程序2 else 当所有条件都不成立时,最后执行此程序 fi ------------------------- if [ 条件判断式1 ] ;then 当条件判断式1成立时,执行程序1 elif [ 条件判断式2 ];then 当条件判断式2成立时,执行程序2 else 当所有条件都不成立时,最后执行此程序 fi ======================================================= if后面可以跟随test的判断,也可以跟随一个命令;猜测本质其实就是判断test或者命令的结果,即判断$?的值 if [ $n1 -gt 100 ]; if ping -c1 192.168.1.1; if ping -c1 192.168.1.1 &> /dev/null ; then echo "up";else echo "down"; fi read -p 'please input command:' cmd;if $cmd read -p 'please input command:' cmd;if `echo $cmd` -------------------------------------------------------------------- 示例1: read -p "please input a number" n1 if [ $n1 -gt 100 ];then echo "$n1 > 100" elif [ $n1 -gt 50 ];then echo "$n1 > 50" else echo "$n1 < 50" fi 示例2: read -p 'please input command:' cmd echo "your command is: $cmd" if $cmd>/dev/null;then echo right else echo wrong exit 1 fi

case条件语句 case语句和if…elif…else语句一样都是多分支条件语句,不过和if多分支条件语句不同的是,case语句只能判断一种条件关系,而if语句可以判断多种条件关系。 这个语句需要注意以下内容: case语句,会取出变量中的值,然后与语句体中的值逐一比较。如果数值符合,则执行对应的程序,如果数值不符,则依次比较下一个值。如果所有的值都不符合,则执行 “*)” (*代表所有其他值)中的程序。 case语句以“case”开头,以“esac”结尾。 每一个分支程序之后要通过“;;”双分号结尾,代表该程序段结束(千万不要忘记,每次写case语句,都不要忘记双分号)。 ====================================================== case $变量名 in "值1") 如果变量的值等于值1,则执行程序1 ;; "值2") 如果变量的值等于值2,则执行程序2 ;; …省略其他分支… *) 如果变量的值都不是以上的值,则执行此程序 ;; esac ------------------------------------------------------- 示例: #!/bin/bash read -p "请输入一个字符,并按Enter确认:" KEY case "$KEY" in [a-z]|[A-Z]) echo "您输入的是字母" ;; [0-9]) echo "您输入的是数字" ;; *) echo "您输入的是其他字符" ;; esac

for循环、for循环开启多进程、如何传入一个动态次数的for循环 ====================================================== for循环 语法一: 这种语法中for循环的次数,取决于in后面值的个数(空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。也就是说,假设in后面有三个值,for会循环三次,第一次循环会把值1赋予变量,第二次循环会把值2赋予变量,以此类推。 for 变量 in 值1 值2 值3 …(可以是一个文件等) do 程序 done 语法二: 初始值:在循环开始时,需要给某个变量赋予初始值,如i=1; 循环控制条件:用于指定变量循环的次数,如i<=100,则只要i的值小于等于100,循环就会继续; 变量变化:每次循环之后,变量该如何变化,如i=i+1。代表每次循环之后,变量i的值都加1。 for (( 初始值;循环控制条件;变量变化 )) do 程序 done ===================================================== 语法一示例: #直接给出列表 for num in 1 2 3 4 5 6; do echo "The number is $num";done #整数列表 for num in {1..6}; do echo "The number is $num";done #返回列表的命令 for num in $(seq 6); do echo "The number is $num";done for num in $( ls ); do echo "The number is $num";done for num in `ls`; do echo "The number is $num";done sum=0;for num in {1..100};do sum=$(($sum+$num)); done ;echo $sum sum=0;for num in {1..100};do let sum+=$num; done ;echo $sum ------------------------ for i in {1..100}; do { if ping -c1 192.168.1.$i &> /dev/null ;then echo 192.168.1.$i is up ; else echo 192.168.1.$i is down ; fi; }& #这里开启多线程了???????? done wait #等待所有子线程结束后再退出 ------------------------ for i in {1..10};do cat >> f1 << EOF aaa bbb EOF #注意,此处EOF不能与上面内容“aaa/bbb”同列 done ------------------------ for i in {1..10};do cat >> f1 <<-EOF aaa bbb EOF #若要在同一行,则在第一个EOF前面加上“-” done ====================================================== 如何传入一个动态次数的for循环 for i in {1..$n};#错误! for i in `seq $n` for i in `eval echo {1..$n}`; #这时才是要的写法;为什么需要这样?猜测:``内是不会识别变量的,这里通过eval来识别$n

while循环、while循环的特殊用法(逐行处理文件的每一行内容) ====================================================== 对while循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。 while [ 条件判断式 ] do 程序 done ------------------------------------------------- SLEEPTIME=10 #生产中实用的小脚本,检测httpd的状态,当httpd挂了,实现自动拉起的功能 while true;do #脚本未实测,可能有问题 if killall -0 httpd &> /dev/null;then : else systemctl restart httpd &> /dev/null echo "xxxxxxxx" >> /data/httpd.log fi sleep $SLEEPTIME=10 done ----------------------------------------------- num1=$[$RANDOM%100] while : ; do read -p 'please input a number:' num2 if [ $num1 -gt $num2 ] ;then echo "$num2 is smaller" elif [ $num1 -lt $num2 ] ;then echo "$num2 is biger" else echo "right!" break fi done echo "game is over" ================================================== while循环的特殊用法 while read line;do 循环体 done < /path/filename #实现功能:逐行读取/path/filename文件的每一行,并且将内容赋值给变量line ---------------------------- df | while read line;do #此处的df就是普通的df命令,可以替换为其他命令,如ls等;其实这个就是另一种形式的特殊用法 循环体 done
until循环:和while循环相反,until循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。

select循环与菜单 ================================================== select循环主要用于创建菜单,将数字顺序排列的菜单项将显示在标准错误上,并显示PS3提示符,等待用户输入 用户输入菜单列表中的某个数字,执行相应的命令 用户输入被保存在内置变量REPLY中 select variable in list do 循环体命令 done select是个无限循环,因此需要用break、exit来终止循环,也可以ctrl+c退出循环 select经常和case联合使用 ================================================ select choice in choice1 choice2 choice3 choice4;do case $choice in choice1) echo you choose $choice ;; choice2) echo you choose $choice ;; choice3) echo you choose $choice ;; choice4) echo you choose $choice ;; *) echo you choose none! ;; esac done

信号捕捉trap ========================================== 信号捕捉trap trap命令的参数分为两部分,前一部分是接收到指定信号时将要采取的行动,后一部分是要处理的信号名。 https://blog.csdn.net/weixin_30703911/article/details/96862888 它有三种形式分别对应三种不同的信号回应方式。 第一种: trap "commands" signal-list 当脚本收到signal-list清单内列出的信号时,trap命令执行双引号中的命令。 第二种: trap signal-list trap不指定任何命令,接受信号的默认操作,默认操作是结束进程的运行。 第三种: trap " " signal-list trap命令指定一个空命令串,允许忽视信号,我们用到的就是这一种。 查看信号种类 kill -l ;trap -l kill默认使用的是信号15,这个信号是可以被捕捉 但是信号9(强杀)是不能被捕捉的 kill -9 PID ==================================================== 示例: 实现功能:持续运行while循环,当捕捉到信号“HUP INT QUIT TSTP”时,执行双引号里的命令,而忽视信号 trap "echo catch signle " 1 2 3 20 trap "echo catch signle " HUP INT QUIT TSTP i=0 while true;do echo $i ((i++)) sleep 1 done 猜测:其实脚本在运行时,是有默认的trap的,只不过trap为空。所以可以在脚本的不同位置修改不同的trap,那么在运行脚本的某个阶段则会执行相应的trap

特殊流程控制语句:exit、continue、break;shift ============================================================================================== exit [返回值] 系统是有exit命令的,用于退出当前用户的登录状态。可是在Shell脚本中,exit语句是用来退出当前脚本的。也就是说,在Shell脚本中,只要碰到了exit语句,后续的程序就不再执行,而直接退出脚本。 如果exit命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。可以通过查询$?这个变量,来查看返回值。如果exit之后没有定义返回值,脚本执行之后的返回值是执行exit 语句之前,最后执行的一条命令的返回值。 ---------------------------------------------------------------------------------------------- 当程序执行到break语句时,会结束整个当前循环。而continue 语句也是结束循环的语句,不过continue 语句单次当前循环,而下次循环会继续。 continue也是结束流程控制的语句。如果在循环中,continue语句只会结束单次当前循环。 continue 用于循环体中,提前结束本轮循环,进入下一轮循环的判断 continue N #N默认为1 break 用于打断循环 break N #N默认为1 ---------------------------------------------------------------------------------------------- 严格来说shift不属于流程控制吧.... shift 可以把脚本传入的参数看成一个列表,由左向右排序;shift就是用于移除左侧的参数,默认移除1个 shift N #N默认为1 例如某个支持批量创建账号的脚本,参数即账号名,但是数据不固定。此时可以利用shift,在while循环中一直对第一个参数进行判断,有参数则进行账号创建,没参数则退出循环
整理思路参照:https://www.cnblogs.com/jiading/p/12302600.html
补充资料:https://blog.csdn.net/w918589859/article/details/108752592
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!