Shell脚本编程基础――Linux基本命令(11)
1.Shell脚本基础(1)shell脚本包含一些命令或声明,并符合一定格式的文本文件 格式要求:首行shebang机制 #!/bin/bash #!/usr/bin/python #!/usr/bin/perl
(2)格式要求脚本代码开头约定: 1、第一行一般为调用使用的语言 2、程序名,避免更改文件名为无法找到正确的文件 3、版本号 4、更改后的时间 5、作者相关信息 6、该程序的作用,及注意事项 7、最后是各版本的更新简要说明(也可以不写) 其实最重要的是第一行,其他行也可以不写,但是为了一个良好的变成习惯,建议还是写上。 (3)脚本调试检测脚本中的语法错误 bash -n/path/to/some_script 调试执行 bash -x/path/to/some_script 会一条一条的调试执行,可以找出哪一句错误了 如图,显示着最后一条有错误 2.变量(1)变量介绍作用: 1、数据存储格式 2、参与的运算 3、表示的数据范围 类型: 字符 数值:整型、浮点型 变量命名法则: 1、不能使程序中的保留字:例如if,for 2、只能使用数字、字母及下划线,且不能以数字开头 3、见名知义 4、统一命名规则:驼峰命名法 (2)bash中变量的种类根据变量的生效范围等标准: 本地变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效 环境变量:生效范围为当前shell进程及其子进程 局部变量:生效范围为当前shell进程中某代码片断(通常指函数) 位置变量:$1,$2,...来表示,用于在脚本代码中调用通过命令行传递给它的参数。 特殊变量:$?,$0,$*,$@,$#,$$ (3)本地变量变量赋值:name=‘value’ 可以使用引用value: (1) 可以是直接字串;name=“root" (2) 变量引用:name="$USER" (3) 命令引用:name=`COMMAND` name=$(COMMAND) 变量引用:${name} $name "":弱引用,其中的变量引用会被替换为变量值 '':强引用,其中的变量引用不会被替换为变量值,而保 持原字符串 显示已定义的所有变量:set 删除变量:unset name (4)环境变量变量声明、赋值: export name=VALUE declare -x name=VALUE 变量引用:$name,${name} 显示所有环境变量: env printenv export declare -x 删除变量: unset name bash内建的环境变量: PATHSHELL USER UID HOME PWD SHLVL LANG MAIL HOSTNAME HISTSIZE― (5)只读和位置变量只读变量:只能声明,但不能修改和删除 声明只读变量: readonly name declare -r name 查看只读变量: readonly -p 位置变量:在脚本代码中调用通过命令行传递给脚本的参数 $1,...:对应第1、第2等参数。$1表示第一个参数,$2表示第二个参数 $0: 命令本身 $#: 传递给脚本的参数的个数 $*: 传递给脚本的所有参数,全部参数合为一个字符串 $@: 传递给脚本的所有参数,每个参数为独立字符串 $@和$* 只在被双引号包起来的时候才会有差异 假设你的脚本运行时你写了三个参数 分别存储在$1 $2 $3中 则"$*" 等价于 “$1 $2 $3 $4" ---》传递了一个参数 而“$@" 等价于 "$1" "$2" "$3" "$4" ---》传递了四个参数 如图,分别使用两种方式将1 2 3 4传给aa.sh和bb.sh,然后取第一个参数,果然发现输出的结果表明$@传递了四个参数,因此取第一个才会是1。 set -- 清空所有位置变量 如图,使用set --后所有变量被清空 PS:引用一位数以上的变量(如上图的$10)时要加{},不然系统会认为是$1和0。 (6)参数左移shift n用于对参数的移动(左移) 如图,参数向左移动了两位(就是删除最左边两个)。由abcdefg变成cdefg 3.退出状态(1)退出状态进程使用退出状态来报告成功或失败 0 代表成功,1-255代表失败 $? 变量保存最近的命令退出状态 正常状态,$?值为0 最后一条失败,$?值不为0 (2)自定义退出状态码exit [n]: 使用exit [n]也可以自定义退出状态码。注意:脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字。 注意:如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码。 4.算术运算bash中的算术运算:help let +,-,*,/,%取模(取余),**(乘方) 实现算术运算: (1) let var=算术表达式 (2) var=$[算术表达式] (3) var=$((算术表达式)) (4) var=$(exprarg1 arg2 arg3 ...) (5) declare ?Ci var = 数值 (6) echo ‘算术表达式’ | bc 乘法符号有些场景中需要转义。 bash有内建的随机数生成器:$RANDOM(0-32767) echo$[$RANDOM%50] :0-49之间随机数 (同理可以使用echo$[$RANDOM%50+1]随机产生1-50之间的随机数) 5.赋值增强型赋值: +=,-=,*=,/=,%= let varOPERvalue 例如:let count+=3 自加3后自赋值 自增,自减: let var+=1 let var++ let var-=1 let var-- 6.逻辑运算(1)与真与真 真 真与假 假 假与真 假 假与假 假 总结:只要有一个假则为假
短路与:若前一个为假,则不再判断第二个值,因为结果必为假。 (2)或真或真真 真或假真 假或真真 假或假假 总结:只要有一个真则为真
短路或:若前一个为真,则不再判断第二个值,因为结果必为真。 7.条件测试判断某需求是否满足,需要由测试机制来实现。专用的测试表达式需要由测试命令辅助完成测试过程。 评估布尔声明,以便用在条件性执行中 若真,则返回0 若假,则返回1 测试命令: test EXPRESSION [ EXPRESSION ] [[ EXPRESSION ]] 注意:EXPRESSION前后必须有空白字符 根据退出状态而定,命令可以有条件地运行 && 代表条件性的AND THEN || 代表条件性的OR ELSE 就是说如果前一条命令输出为0,就执行&&后面的内容,否则执行||后面的内容。 使用这种方法就不用每次使用$?调取结果了 另外,使用[]可以判断是否有值,如有则输出0,如没有则输出1 8.bash的测试(1)数值测试-gt 是否大于 -ge 是否大于等于 -eq 是否等于 -ne 是否不等于 -lt 是否小于 -le 是否小于等于 (2)字符串测试==是否等于 > ascii码是否大于ascii码 < 是否小于 !=是否不等于
=~ 左侧字符串是否能够被右侧的PATTERN所匹配(部分内容被匹配即可) 注意: 此表达式一般用于[[ ]]中;扩展的正则表达式 -z "STRING“ 字符串是否为空,空为真,不空为假 -n "STRING“ 字符串是否不空,不空为真,空为假
注意:用于字符串比较时的用到的操作数都应该使用引号 (3)文件测试使用方式为选项加文件:-x FILE 存在性测试: -a 判断文件存在则为真 -e同-a 存在性及类别测试: -b判断文件为块设备文件则为真 -c判断文件为字符文件则为真 -d判断文件为目录文件则为真 -f判断文件为普通文件则为真 -h判断文件为软链接文件则为真 -L同-h
-p是否存在且为命名管道文件 -S是否存在且为套接字文件
文件权限测试: -r判断当前用户对该文件可读时为真(root永远为真) -w判断当前用户对该文件可写时为真(root永远为真) -x判断当前用户对该文件可执行为真(只要有任意位置有x,root则为真)
文件特殊权限测试: -u判断该文件有suid权限为真(对于非二进制文件加上suid即使为真也无效) -g判断该文件有sgid权限为真(对于非二进制文件加上sgid即使为真也无效,目录有效) -k判断文件是否有sticky权限(对于普通文件没有意义)
文件大小测试: -s判断文件(非目录)为非空时为真
文件是否打开: -N判断文件在上一次读取后被改过则为真。 -O判断文件的owner为当前用户时为真 -G判断文件的group是当前用户的主组时为真
双文件测试: 使用方式为FILE1 -ef FILE2 -ef 判断两个文件是硬链接时为真 -nt判断前一个文件的mtime新于后一个文件时为真 -ot判断前一个文件的mtime旧于后一个文件时为真 (4)组合测试条件第一种方式: COMMAND1 && COMMAND2 并且 COMMAND1 || COMMAND2 或者 ! COMMAND 非 如:[[ -r FILE ]]&&[[ -w FILE ]] 第二种方式: EXPRESSION1 -a EXPRESSION2 并且 EXPRESSION1 -o EXPRESSION2 或者 ! EXPRESSION 必须使用测试命令进行 9.接受输入使用read来把输入值分配给一个或多个shell变量 -p 指定要显示的提示 read -p “Enter a filename: “ FILE -s静默输入,一般用于密码 (注意,必须是sp如果一起使用必须是-sp,不能用-ps)
-n N 指定输入的字符长度N -d ‘字符’ 输入结束符(就是当输入指定结束符时就算输入结束,会自动跳到下一行) -t N TIMEOUT为N秒 (给用户的输入做限时规定。若超出-t参数后所规定的时间值后,脚本将终止用户的输入,可单独使用也可和其它参数配合连用。)
read 也可以从标准输入中读取值,给每个单词分配一个变量(注意:不支持管道)。如果变量数少于单词数,则所有剩余单词都被分配给最后一个变量
read 变量名1 [变量名2] < 文件名
也可以使用<<<直接导入具体值: read 变量名1 [变量名2]<<< "值1 [值2] ..." 10.防止扩展反斜线()会使随后的字符按原意解释 如图,此时我们只想使用$作为美元符号,因此需要加上,如果不加则意思为引用变量5。但是我们没有定义变量5,所以为空。
也可以加引号来防止扩展 单引号(’)防止所有扩展 双引号(”)也防止所有扩展,但是以下情况例外: $(美元符号) - 变量扩展 `(反引号) - 命令替换 (反斜线) - 禁止单个字符扩展 !(叹号) - 历史命令替换 11. bash的配置文件按生效范围划分,存在两类: 全局配置: /etc/profile /etc/profile.d/*.sh /etc/bashrc 个人配置: ~/.bash_profile ~/.bashrc 12.shell登录的两种方式(1)交互式登录:(1)直接通过终端输入账号密码登录 (2)使用“su - UserName”切换的用户 执行顺序:/etc/profile--> /etc/profile.d/*.sh ; ~/.bash_profile --> ~/.bashrc-->/etc/bashrc
bash已经定义好了,只要登录bash,就先加载/etc/profile文件 通过/etc/profile中的代码调用/etc/profile.d/ 下所有的.sh文件 当读完所有.sh文件后,返回/etc/profile结束读取。然后bash会接着自动读取~/.bash_profile文件 如图,~/.bash_profile文件中的命令调用~/.bashrc文件 而~/.bashrc文件中的命令又调用了/etc/bashrc文件 其实在/etc/bashrc文件中也有命令调用/etc/profile.d/*.sh文件,但是由于之前已经调用过了,里面会判断就不再调用了
总结:bash自身只会读/etc/profile和 ~/.bash_profile 其他都是在读取这两个文件时调用读取出来的 (2)非交互式登录:(1)su UserName (2)图形界面下打开的终端 (3)执行脚本 (4)任何其它的bash实例 执行顺序:~/.bashrc --> /etc/bashrc --> /etc/profile.d/*.sh 总结:非交互式登陆下,bash自身只读取~/.bashrc 文件,然后文件中调用/etc/bashrc文件中又继续调用/etc/profile.d/*.sh
※举个具体例子加深理解吧: 如图,我们分别在这5个文件中加上5段定义变量的话。此时查看5个变量的值,发现为空。因为此时并没有重新登录所以这些文件不重新读取。 于是我们退出并重新登陆。 此时可以看到,分别有定义的值了。
然后我们将C3改成C6 (改完之后目前还是原来的结果,因为没有重新登录) 然后我们使用非交互式登陆root 注意:非交互式登陆有一个特点,它不是登陆一个新的环境,会继承之前shell的所有变量,当然了,如果重新赋值了,它当然会被重新覆盖掉。 因此我们发现变量的值仍然不变。因为即使修改了C,但是非登录shell并不读取~/.bash_profile文件,所以不会被重新赋值。 然后我们退出这个shell到之前的shell,将/etc/bashrc中的E5改为E7。 因为从来都没有重新读取过,因此此时读取变量的话,仍然是12345这5个值。 然后再非交互式登陆到root下, 发现E的值改变了,因为非交互式登陆是需要读取/etc/bashrc文件的。 然后我们再退出到上一个shell,将B2改成B8 此时读取变量仍然是12345, 然后使用非交互式登陆到liubei用户下,发现B的值也改变了。因为非交互式登陆也需要读取/etc/profile.d/*.sh文件的。 然后我们再退出,将D4改为D9 发现变量仍然为 因为我们改的是root下的.bashrc文件,而liubei用户读取的应该是自己家目录的.bashrc文件,因此D的值不变。 然后我们退出并使用交互式登陆liubei用户 此时变量为: 因为交互式登录不会继承之前shell的内容而是全部重新读取,而liubei用户又只会读自己家目录下的.bash_profile文件,而不会读取root下的.bash_profile文件,因此C的值为空。同理,也不会读D的值。因此这两个变量均为空。
PS:修改文件后需生效有两种方法: 1重新启动shell进程(像刚才举例子中的方式) 2使用. 或source 例如: . ~/.bashrc 13. $-变量h:hashall,打开这个选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选项关闭 i:interactive-comments,包含这个选项说明当前的shell 是一个交互式的 shell。所谓的交互式shell,在脚本中,i选项是关闭的。 m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等。 B:braceexpand,大括号扩展 H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的一个历史命令,“!n”返回第 n 个历史命令 正常查询时全部开启,某些变量可以通过命令开启或关闭 如图,关闭h选项。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |