shell(一)
基本使用
执行shell脚本 文件后缀为 .sh ,Linux下的shell解释器众多,如Bourne Shell 和 Bourne Again Shell所代表的的/bin/sh和/bin/bash,但也无需分的太清楚。一般在行首使用#!bin/sh来指定解释器。echo 表示向窗口输出文本/打印
编辑完成后可对文件做个chmod权限控制,根据自己需要添加就行了。使用/bin/sh运行文件即可
./test.sh #加./ 指定路径 ,教程说一定要加,但其实不加好像也没什么关系
备注:权限设置之数字表示法
三种权限分别是可读(r)、可写(w)、可执行(x),使用八进制数分别代表4、2、1。linux下文件权限表共10位,除了表示文件类型的第一位,后九位分为三组,其意义分别为:文件拥有者、系统群组、系统其他用户
如设置某文件给系统拥有者为可读/写/执行,群组可读/执行,其他用户可执行。则该文件权限为:-rwxr-x--x 按照数字对应即为:751
Shell变量
shell赋值变量的规则大抵和其他语言类似,唯一注意的是变量名和等号之间不能有空格。
使用变量只需在变量名前加$符,最好在变量名外添加一个识别变量边界的花括号。如:
echo ${name}
只读变量不可更改,也不可被unset删除。从这里看出shell是逐行运行的,前面正常的代码还是会正常输出
但是也同样发现一个问题,当变量被unset后,此时使用readonly定义一个已经被删除的变量名后打印出来,会出现一个打印了空白行的效果(也可能是回车了)
而变量被unset并readonly后,重新对已删除的变量名进行重新赋值,则继续报变量名已读的错误
对此目前我的理解是unset只是给原变量更换了新的空白值,并没有真正把name整个变量删除掉。所以才会导致当我添加readonly后继续输出会显示一个空白行。
- 变量类型
局部变量;在脚本或命令中定义。当前脚本有效
环境变量;所有程序都可访问,部分程序依靠环境变量来运行
Shell变量;保证Shell正常运行的变量
Shell字符串
字符串使用单/双引号
- 单引号是原样输出引号内所有字符串,故不可在单引号内使用变量,也不可使用转义。
- 双引号则相反,可使用双引号也可以使用转义
字符串长度获取
${#str} 得到变量str字符串长度(包含首尾空格)
字符串截取
${str:frist:last} 获取字符串从first(含)开始到last(含)结束的子串。
查找子串位置
·expr index "$str" ab· 获取ab子串在变量str中的位置,注意expr外面是反引号。
需要注意的是,子串位置是从1开始计算,而字符串截取是从0开始计算。查找子串时,首先会查找“ab”串是否在变量中存在,若存在则返回该子串首次出现位置,不存在则反馈“a”串在str中的首次出现位置
Shell数组
shell只有一维数组,并且大小不受限制。唯有下标与其他语言的数组是同步的——从0开始。允许下标不连续,大小也无限制。
- 数组的创建
arr=(v1 v2 v3…)
数组的读取
arr{[n]} 读取追的指定下标,当指定的元素 arr{[@]} 读取数组所有元素
数组长度
length=${#arr[@]} 数组总长 length=${#arr[n]} 指定数组元素长度
注释
单行注释使用#
多行注释使用:< < EOF +EOF配合使用
传递参数
在linux 下执行脚本时,需保证该脚本是否有可执行权限。执行脚本例如:
./test.sh p1 p2 p3 … pn代表参数
代码中引用参数时,$0代表当前文件名称,$1才代表第一个参数,以此类推……
当需要精准地根据位置填入参数时,建议使用单引号将参数括起来。
$ * 与 $@
$ * 将其视为一个参数传递传入:
$@则将其视为三个参数分批传入
运算符
原生bash不支持运算符,但一般用命令(如expr)实现
算数运算符
val=expr 1 + 1
加号两边必须带空格,否则直接输出"1+1"val=expr 2 \* 1
乘法前面需要加个反斜杠转义val=expr=2 / 6
除法结果只能为正整数,最小为0,去掉小数val = $a
赋值, 将变量a的值赋给val
[ 2 == 6 ] 比较,相等时得 1,不相等得 0
注意:比较双方左右必须有空格,算数运算符支持数字和变量关系运算符
-eq:判断相等 相等则返回ture
-ne:判断不相等,不相等返回ture
-gt:判断大于,大于则返回ture
-lt:判断小于,小于返回ture
-ge:判断大于等于,是则返回ture
-le:判断小于等于,是则返回ture布尔运算
!:非。结果为T返回F,为F返回T
-o:或。其中一边为T则为T,都为F才返回F
-a:与。两遍均为T才返回T,否则返回F逻辑运算符
&&:and,即上面的-a
||:or,即上面的-o字符串运算符
= 检测字符串是否相等 相等返回T
-z 字符串长度是否为0 0返回T
-n 字符串长度是否不为0,不为0返回T
$ 判断字符串为空 空返回T文件检测运算符
-r 是否可读 | -w 是否可写 | -x 是否可执行 | -f 是否为普通文件
-d 是否为目录 | -s 判断文件是否非空 | -e 判断文件是否存在
Shell 输出命令
- echo
echo后的双引号可加可不加
转义字符: \ 。转义需要使用echo -e开启
输出结果定向至指定文件夹: >文件名
输出日期 echodete
date使用反引号括起 - printf
模仿的是C语言中的printf(),使用printf的脚本比echo的移植性好。printf一般用于格式化输出,指定字符串间距、对齐方式等
例如:printf "%-10s %-8s %-4s\n" "%-4.2f"
%-10s:指定一个宽度为10的字符串长度,-表示左对齐,所有字符都会显示在这个宽度里
%-4.2f:将格式转化为小数,整数+小数共4位且小数保留两位
Shell test命令
- 文件测试
test一般用于检查谋而条件是否成立,可比较字符、数值、文件三个方面的测试
-e:文件存在即为真
-r:文件存在且可读为真
-w:文件存在且可写为真
-x:文件存在且可执行为真
-s:文件存在且至少有一个字符为真
-d:文件存在且是一个目录为真
-f:文件存在且为普通文件为真
Shell 流程控制
分支
if …… then …… elif …… then …… else …… then …… fi
也可写成同一行,使用分号将不同的语句端隔开。一般用在终端命令提示符
if …… ; then ……; elif …… ; then …… ;else ……; then ……; fi
for循环
in 列表可包含文件名、字符串等for var in v1 v2 v3 … do ……$var …… done
同样可写成一行,使用分号隔开语句:
for var in v1 v2 v3 …; do …… ; done
while循环
与for 循环类似,格式如下while …… do …… done
除了基本的循环,while还支持通过read 读取键盘输入的信息:
while read var
do
……$var……
done
注:在控制条件时,a=expr $a + 1
和let "a ++"
的想过是相同的,但是let命令比前者运行速度更快,但是使用expr的兼容性更好一些until 循环
与while类似,只是刚好相反,当判断条件为ture时停止循环until …… do …… done
case esac分支
value可取变量或常量。模式后必须跟)。一旦匹配成功,运行其中所有代码直至;;处。若无匹配到,则进入*模式运行其中代码。该模式还支持正则表达式匹配
```
case value in
value1)
……
;;
value2)
……
;;
value3)
……
;;
*)
……
;;
esac
```
Shell 函数
- 格式
[ function ] funName [ ( ) ]
{
方法体;
……$1……
……$2……
……$3……
……
……${10}……
……$11{}……
……
return [ int 0~255; ]
} - 注意
可使用function fun()或直接fun()无参定义。调用函数直接写函数名即可
返回值:返回值只能是数值,且范围是0~255。(教程说若无return 语句则最后一句作为返回值。实测后并不是,而是返回0)
函数外返回值调用时使用$?
参数调用时使用$n,当n>=10则必须使用${n}
重定向
- 输出重定向
通过>(覆盖原内容) 或 >>(追加原内容)重定向至指定文件,格式:command1>file1
将echo标准输出的终端重定向为user文件
输出重定向会将原内容覆盖,若不想覆盖则使用>>进行追加
- 输入重定向
一般使用输入重定向是想要对文本内容进行统计,使用linux的wc命令即可统计文本wc [-c 字节数]/[-w 单词数]/[-l 行数] [文件名]
也可使用while逐行读取全部内容
>>表示使用指定分界符作为命令输入结束的标志,只有输入分界符后才结束内容读取。使用情况如下:
同时将输入/输出重定向,将echo输出的文本加上 user文件本身的内容一起读取后追加至new文件里
文件包含
在sh文件内部可调用外部sh脚本,便于封装一些公用代码作为独立文件,被调用的文件可无需执行权限
- 调用方式
. filename
注:点号后有空格source filename