shell
简介
Shell就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给系统。它为用户提供了一个向Linux发送请求以便运行程序的接口系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。 Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,又是一种程序设计语言(就是所说的shell脚本)。而实际中,最常用的是shell script。换一种说法也就是,shell script是利用shell的功能所写的一个程序,这个程序是使用纯文本文件,将一些shell的语法与指令写在里面,然后用正规表示法,管道命令以及数据流重导向等功能,以达到我们所想要的处理目的。
语法
格式
#!
shell 脚本文件开头通过 #!定义使用的编译器类别
#! /bin/bash
Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(
/usr/bin/sh
或/bin/sh
) - Bourne Again Shell(
/bin/bash
) - C Shell(
/usr/bin/csh
) - K Shell(
/usr/bin/ksh
) - Shell for Root(
/sbin/sh
)
注解
注解实现
#--------------------------------------------------------
#
# 这部分是注解,文件解析的时候会默认忽略这部分内容
#
#--------------------------------------------------------
echo "这个是正文。" # 你可以添加独立的,也可以在语句之后添加
:<<`
asdfasdf
asdf
asdf
`
:<<EOF
ASDFASDFASDFASF
EOF
:<<!
ASDFASDFASD
!
# 上面三个是多行注释,<<tag...tag 符号代表 Here Ducument 重定向方式
变量的定义及使用
变量的定义
val=123
cal="123" # 需要注意的是等号的两边不能有空格
变量的使用
temp=$val
temp="abc"$val
temp="abc"${val} # 变量的使用可以是 $val 也可以 ${val},推荐后一种,这样可以明确变量边界
关于引号
类似于PHP中的引号规则,双引号相较于单引号有更多的解析能力,可以解析字符中的变量、转义字符等。
echo "aaa${val}" # aaa123
echo 'aaa${val}' # aaa#{val}
echo 'aaa'${val} # aaa123
只读属性
readonly val # 只读属性不能修改
删除变量
unset val # 删除变量 [-fnv] f:对应的方法 n:对应的拥有nameref属性的变量,引用变量不会 v:对应的自身和引用变量
变量类型
- 局部变量 仅当前shell实例可以进行访问
- 环境变量 除shell实例之外,启动的程序也是可以进行访问的
- shell变量 定义的用于保证shell运行的变量,包括局部和环境两种
字符串
单引号
- 单引号内的任何字符都会进行原样输出,无法使用变量
- 多个单引号可以进行字符串的拼接
双引号
- 双引号内可以使用转义字符等特殊字符,可以引用变量
- 多个双引号可以进行字符串的拼接
拼接
- 通过两个字符串拼接
string = 'aaa'${val}'bbbbb'
- 可以通过在双引号内使用变量
string = "aaa${val}bbbb"
长度
可以通过 ${#val}
的方式,输出字符串 val
的长度
截取
通过 ${val:start:length}
的方式对val
进行截取,截取时不包括 start
字符
查找
通过 ` expr index "$string" io `
对字符串string
进行查找,io
的意思是搜索i
或o
,谁先出现就查谁
数组
创建
数组可以通过
-
list = (a b c ...)
-
list = (
a
b
c
...)
-
list[0] = a
list[n] = b
这样定义的好处是,下标不需要连续,也没有上限
读取
数组的读取直接通过下标可以获得${list[index]}
获取全部可以用 ${list[@]}
或者 ${list[*]}
长度
通过 ${#list[@]}
或者 ${#list[*]}
获取整个数组的长度,某个元素的长度可以用 ${#list[index]}
参数传递
$n
通过$n
可以获取到命令行参数,所有的。
$#
获取传入参数的个数
$* 和 $@
他们都必须搭配""
使用,不同的是$*
将传入的所有参数都作为一个整体,而$@
则是将参数作为一个数组。
$$
当前运行的进程ID
$!
后台运行的最后一个进程ID
$-
作用同 set 命令相似
$?
命令退出的状态,0 为正常,其他为执行有问题。
- 如果参数中有空格,可以使用引号括起来,便于脚本识别和使用
- 中括号的使用,中括号和其中的参数应该有空格隔开
运算符
shell 支持多种运算编程:
- 算术运算
- 布尔运算
- 关系运算
- 字符串运算
- 文件测试运算
原生的bash
不支持简单的数学运算,可以通过 awk
和 expr
命令执行
expr
expr
是一个表达式计算工具
- 表达式和运算符之间需要有空格
- 需要被
` `
包裹才可以使用
运算符
算术运算符
-
+
-
-
-
*
`expr $a \* $b`
乘法需要用转义符进行处理才能使用 -
/
-
%
-
=
赋值
-
!=
[ $a != $b ]
注意中括号和参数之间的空格 -
==
同上
关系运算符
关系运算符只能适用数字,除非字符串的内容是数字,不然不适用。
-
-eq
相等equal
-
-gt
大于greater than
-
-lt
小于less than
-
-ge
大于等于greater than and equal to
-
-le
小于等于less than and equal to
-
-ne
不等于not equal
使用的时候通过
[]
包含进行使用
布尔运算符
-
!
非 -
-o
or
-
-a
and
使用的时候也是通过
[]
包含使用
逻辑运算符
-
&&
-
||
使用的时候需要搭配
[[ ]]
包含使用
字符串运算符
-
=
是否相等 -
!=
是否不等 -
-n
长度是否不为零 -
-z
长度是否为零 -
$
是否不为空搭配
[]
包含使用
文件测试运算符
文件测试运算检测Unix文件的属性。
操作符 | 说明 | 举例 |
---|---|---|
-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。 |
其他检查符:
- -S: 判断某文件是否 socket。
- -L: 检测文件是否存在并且是一个符号链接。
echo
用于文字的输出。
echo string
可以用来输出string
字符,string
可以是单引号、双引号,也可以是指令。单双引号的用法没变,指令需要用` `
符号包含,显示执行的结果。也可以通过>
符号将结果输出到指定文件中,eg:echo "this is string" > file.txt
。如果想要对输出结果进行换行显示,需要增加-e
属性,用于开启转义,eg:echo "this is \n"
换行;echo "this si \c"
不换行
printf
printf
作为shell的另一种输出方式,对比echo,它具有更好的移植性、更强的功能。
test
用于检测某个条件是否成立,它可以检测数字、字符串、文件。
test
可以代替运算符使用过程中的[]
符号。
流程控制
if...elif...else...fi
流程命令可以写成多行也可以写成一行,每个逻辑段落用;
进行分割。
if test $[a]
then
......
elif test $[b]
then
......
else
......
fi
for
for var in list
do
......
done
也可以
for ((i=0;i<5;i++)) # 通常情况下 shell 变量调用需要加 $,但是 for 的 (()) 中不需要
do
......
done
# 变形
val = 5;
for (( $val < 10 )) # 使用的时候需要通过 `$` 修饰
do
echo "。。。。。。"
let "val++" # let 方法可以不用 `$` 修饰,使用变量
done
for ((arg;arg1:next))
do
......
done
写成一行
for var in list;do;......;done;
while
while ((...))
do
......
done
无限循环:
while :
do
......
done
while true
do
......
done
for ((;;))
until
与while
刚好相反,until
直到判断为true,停止循环。
until test $[...]
do
......
done
case
case $a in
1)
......
;; # break 一致
*) # default 值
......
;;
esac
结束循环
与其他语言类似,结束循环可以使用break
和continue
break # 结束循环并推出
continue # 结束当前循环
自定义函数
可以通过自定义一个函数,进行全局调用。不过,必须要先定义才能使用,所以函数应该优先放在开始的地方。
# 定义的方式可以带 functino 字样,也可以不带
functino damo() {
......
return int; # 返回信息通过 return 返回一个数值 [0-255]
}
damo() {
...... # 也可以不用 return 默认返回最后一条语句的执行结果
}
damo # 调用函数直接通过函数名调用
damo 1 3 4 5 6 # 调用的时候也可以带参数调用,函数内通过 $1 $2... 方式进行获取,第十个参数开始,需要通过${10} 的方式获取
echo $? # $? 可以用来获取上一条语句的执行结果,如果上一条语句是执行函数,将会返回函数的返回值
输入 /输出重定向
默认情况下,Unix 系统会从一个标准输入的地方获得一个输入,并将结果输出到标准输出的地方,而这两个地方就是你的终端。如果想要修改输入、输出的位置,那就需要进行重定向。
-
>
输入重定向<
输入重定向 -
>>
输出追加 -
>&
输出合并<&
输入合并 -
<<tag
以tag开始到tag结束,中间的内容作为输入command <<tag # tag 可以是任意字符 ...... tag # tag 顶格,前后都没有内容,包括空格和table
文件描述符
Unix 在执行命令的时候会打开三种文件:输入文件(0)、输出文件(1)、错误文件(2)。描述符可以在语句中明确操作的文件类型。
command > file # 默认情况下,这条语句代表将输出文件重定向到 file 中
command 2> file # 通过添加文件描述符,可以将特定文件进行重定向输出
command > file 2>&1 # 将输出文件和错误文件合并之后输出到 file
/dev/null
这个文件是一个比较特殊的文件,它接受的任何内容都会被丢弃,也不会被查到任何信息。所以可以通过重定向到这个文件,用来达到 无输出的目的。
command > /dev/null 2>&1
包含文件
脚本中可以引用其他的文件,将其内容引入到自己文件中,可以等同看作文件的合并。
. filePath # 通过 . 引入
source filePath # 通过 source 引入
被引入的文件可以没有可执行权限,文件中定义的变量也可以在本地使用。
学习资源来自菜鸟教程(https://www.runoob.com/linux/linux-shell-io-redirections.html)