基本语法
变量
变量的使用
生成变量时必须注意,变量=
前后不能有空格。
读取变量时需要在变量前加$
美元符,或者${}
美元符加花括号,使用花括号为了帮助解释器识别变量的边界。
示例:
name="DonYau"
echo $name
echo ${name}
复制代码
与此同时可以通过${#name}
获取变量的长度
read 获取用户的输入
read命令从标准输入(键盘)或另一个文件描述符中接受输入。在收到输入后,read命令 会将数据放进一个变量。使用read时,可以设置-t n
来设置一个定时器,当计时器过期后,read会返回一个非零退出状态码
例如:
echo -n "Enter your age:"
read age
复制代码
数组
格式:names=(value1 ... valuen) 数组元素之类采用空格隔离
可以使用索引值对数组进行赋值:
names[0]=name
names[1]=age
复制代码
读取数组的某个值:
echo ${names[0]}
index=1
echo ${name[$index]}
复制代码
显示整个数组的值:
echo ${name[*]}
echo ${name[@]}
复制代码
删除数组中的某个值:
unset name[1]
//删除整个数组
unset name[*]
复制代码
获取数组的长度
echo ${#name[*]}
echo ${#name[@]}
输出数组的所有值
echo ${name[*]}
echo ${name[@]}
复制代码
test命令
test命令可以判断三类条件:
- 数值比较
- 字符串比较
- 文件比较
数值比较
运算符 | 含义 |
---|---|
-eq | 等于 |
-ne | 不等于 |
-gt | 大于 |
-lt | 小于 |
-ge | 大于或者等于 |
-le | 小于或者等于 |
例如:
value1=10
if [ $value1 -gt 5 ];then
echo "$value1 大于 5"
fi
复制代码
字符串比较
运算符 | 含义 |
---|---|
str1 = str2 | 检查str1是否和str2相同 |
str1 != str2 | 检查str1是否和str2不相同 |
str1 < str2 | 检查str1是否比str2小 |
str1 > str2 | 检查str1是否和str2大 |
-n | 检查str1的长度是否非0 |
-z | 检查str1的长度是否为0 |
注意:在字符串使用比较符时,大于号和小于号必须转义,否则shell会把它们当作重定向符号
例如:
value1=a
value2=b
if [ $value1 = $value2 ];then
echo "两个值是否相等"
fi
if [ $value1 \> $value2 ];then
echo "value1 大于 values"
fi
复制代码
文件比较
运算符 | 含义 |
---|---|
-d | 文件是否存在,且为目录 |
-e | 文件是否存在 |
-f | 文件是否存在,且为普通文件 |
-r | 文件是否可以读 |
-s | 文件存在,且大于0 |
-w | 文件存在且可写 |
-x | 文件存在且可执行 |
复合条件
- [ condition1 ] && [ condition2 ]
- [ condition1 ] || [ condition2 ]
括号的使用
双括号
双括号允许在比较过程中使用高级数学表达式
例如:
value=10
if (( $value ** 2 > 19 )); then
echo "大于19"
fi
复制代码
双方括号
双方括号里的expression使用了test命令中采用的标准字符串比较。但它提供了test命 令未提供的另一个特性——模式匹配
\\使用了双等号==,双等号将右边的字符串(*e*)视为一个模式, 并应用模式匹配规则
value="shell find"
if [[ $value == *e* ]]; then
echo "符合"
fi
复制代码
使用结构化命令
base shell的if语句会运行if后面的命令,如果该命令的退出状态码是0,这命令成功运行,位于then部分的命令就会被执行。如果退出状态码是其他值,then部分的命令就不会被执行。
if-then
格式:
if command
then
command
fi
复制代码
if-then-else
格式:
if command
then
commands
else
commands
fi
复制代码
if-then-elif
if command
then
command
elif command
then command
command
fi
复制代码
case
例如:
value=2
case $value in
1 | 2)
echo "1或者2";;
3)
echo "3";;
*)
echo "other";;
esac
复制代码
for
格式:
for var in list
do
commands
done
复制代码
默认情况下,base shell会将空格
、制表符
、换行符
当作字段分隔符。
更改字段分隔符
\\定义单个IFS字符
IFS=$'\n'
\\定义多个IFS字符
IFS=$'\n':;
复制代码
while
格式:
while test command
do
other commands
done
复制代码
循环的输出
在shell脚本中,可以对循环的输出使用管道或进行重定向。这可以通过在done命令之后添加一个处理命令来实现。
例如:
for (( i = 1; i < 10; i++ ))
do
echo "The number is $a"
done > test.txt
复制代码
函数
函数定义
在shell中使用函数时,必须先定义函数,否则会报错误。如果重新定义了函数,新定义的函数会覆盖原函数,并且不会产生任何错误。
格式:
//第一种
function name {
commands
}
//第二种
name() {
commands
}
复制代码
函数变量
函数内部使用的任何变量都可以被声明成局部变量。要实现这 一点,只要在变量声明的前面加上local关键字,该关键字保证了变量只局限在该函数中。倘若不使用local关键字,即使是在函数中申明的变量,在外部也可以访问。
函数参数
函数可以使用标准的参数环境变量来表示命令行上传给函数的参数。在函数内部,通过$#
获取参数的个数,$0
获取函数的名称,$1
获取第一个参数,$2
获取第二个参数,以此类推
例如:
function log() {
echo $0
echo $#
echo $1
echo $2
}
log a 2
复制代码
将数组变量当作单个参数传递的话,将不会起作用,函数只会取数组变量的第一个值。因此,可以将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。在函数内部,可以将所有的参数重新组合成一个新的变量。
例如:
function log() {
local a
a=$(echo "$@")
echo ${a[*]}
}
array=(1 2 3 4 5)
log ${array[*]}
复制代码
函数返回值
每个函数都有返回状态码。默认情况下,函数的退出状态码是函数中最后一条命令的返回退出状态码。可以使用$?
来确定函数的退出状态码。不建议使用默认的函数状态码,因为最后一条命令运行成功不代表中间的命令都能运行成功。
函数的返回值必须小于255,任何大于256的值都会产生一个错误的值。
介于以上情况,采用另外一种输出方式,例如:
function log() {
echo 300
}
result=$(log)
echo $result
复制代码
若要从函数中返回数组时,可以使用echo
按正确的顺序输出单个数组值。
例如:
function log() {
local a=(1 2 3 4 5)
echo ${a[*]}
}
result=$(log)
echo $result
复制代码
基本操作
echo 打印指令
输出命令一般有三个格式:
- 直接输出
- 单引号概括输出
- 双引号概括输出
单引号内无法读取变量的值,例如
age=18
echo '$age'
$age
复制代码
当双引号概括输出时,若读取变量后直接拼接字符串,需要使用${}
方式读取变量,例如:
age=18
echo "$age岁"
??
echo "${age}岁"
18岁
复制代码
默认情况下,echo在每次调用后会添加一个换行符,同时也可以使用-n
忽略行号符,例如:
echo "male";echo "female"
male
female
echo -n "male";echo "female"
malefemale
复制代码
装逼模式,彩色输出
//输出加粗红色字体
echo -e "\033[01;31m颜色字体\033[0m"
颜色字体
// /03[4m 下划线
// /033[5m 闪烁
复制代码
上面输出格式中01表示加粗,31表示是红色,后面\033[0m表示恢复所有的属性为原来的默认值
字体色号 | 颜色 | 背景色号 | 颜色 |
---|---|---|---|
30 | 黑色 | 40 | 黑色 |
31 | 红色 | 41 | 红色 |
32 | 绿色 | 42 | 绿色 |
33 | 黄色 | 43 | 黄色 |
34 | 蓝色 | 44 | 蓝色 |
35 | 紫色 | 45 | 紫色 |
36 | 深绿色 | 46 | 深绿色 |
37 | 白色 | 47 | 白色 |
cd 遍历目录
cd 命令可接受相对路径和绝对路径
ls 显示当前目录的文件和文件夹
ls命令支持定义过滤器,通过过滤器决定输出哪些文件或目录。
可以使用简单匹配字符:
?
代表一个字符*
代表一个星号[]
代表元字符或者[a-c]
代表范围[!a]
使用感叹号将不需要的内容排除在外
在使用参数过程中,可以组合参数使用,例如:
ls -aF
./ .putty/
../ .sogouinput/
.CFUserTextEncoding .ssh/
.DS_Store .templateengine/
.IdentityService/ .viminfo
.ServiceHub/ .yarnrc
复制代码
参数 | 作用 |
---|---|
-F | 区分文件与文件夹,文件夹后面会带/斜杠 |
-a | 显示隐藏文件 |
-R | 递归显示 |
-l | 显示文件的相关信息 |
touch 创建文件
例如:
touch data.txt
复制代码
cp 复制文件
格式:cp [file1] [file2]
格式:cp [file1] [file2] directory 该命令必须在directory存在的情况下使用
注意当使用-R拷贝文件夹时,如果file2文件夹已经存在会在file2在创建file1的递归文件
当执行复制时,如果file2文件已经存在,则会覆盖file2的文件
参数 | 含义 |
---|---|
-i | 如果file2存在时,询问是否覆盖 |
-R | 递归复制整个目录 |
-f | 如果对象已经存在则先删除 |
mv 移动或重命名
格式: mv [file1] [file2]
格式:mv [file1] [file2] directory
参数 | 含义 |
---|---|
-i | 如果file2存在时,询问是否覆盖 |
-R | 递归复制整个目录 |
rm 删除文件
格式: rm [file]
格式: rm -r directory
支持使用通配符成组的删除文件
参数 | 含义 |
---|---|
-i | 询问是否删除 |
-f | 强制删除 |
-r -R | 直接删除普通文件,如果是路径就会一次删除下一级路径和文件 |
mkdir 创建目录 rmdir 删除目录
mkdir
格式: mkdir directory
参数 | 含义 |
---|---|
-p | 创建路径中缺失的父目录 |
rmdir
格式: rmdir directory
该命令很少使用,因为该命令只能删除空目录
参数 | 含义 |
---|---|
-p | 创建路径中缺失的父目录 |
file 查看文件类型
格式: file [file]
cat 查看文件内容
格式: cat [file]
参数 | 含义 |
---|---|
-n | 给所有的行加上行号 |
-n | 给只有文件的行加上行号 |
find 文件查找
格式: find base_path
列出当前目录及子目录下的所有文件和文件夹
根据文件名或正则表达式匹配
格式:find base_path -name
例如:
//查找当前目录下以“.txt”结尾的文件
find . -name "*.txt"
//查找当前目录下以“.txt”或“.pdf”结尾并忽略大小写的文件,“\(\)”是指将括号内的内容视为一个整体
find . \( -iname "*.txt" -o -iname "*.pdf" \)
复制代码
根据文件路径匹配
将文件路径作为一个整体进行匹配
格式: find base_path -path
例如:
find . -path "*txt"
复制代码
使用否定参数
例如:
//查找当前目录下不以“.txt”结尾的文件
find . ! -name "*.txt"
复制代码
基于目录的深度搜索
格式:
-maxdepth num
最大深度num-mindepth num
最小深度num
例如:
//查找当前目录及子目录下以“.txt”结尾的文件
find . -maxdepth 2 -name "*.txt"
复制代码
基于文件类型搜索
-type
对文件类型进行过滤
-type f
普通文件 -type d
目录
基于文件大小搜索
例如:
//搜索大于2k的文件
find . -type f -size +2k
复制代码
删除匹配的文件
例如:
//删除大于2k的文件
find . -type f -size +2k -delete
复制代码
跳过特定的目录
例如:
find . \( -name ".git" -prune \) -o \( -type f -print \)
复制代码
gzip 压缩文件 gunzip 解压文件
gzip
格式: gzip [file]
gunzip
格式: gunzip [file]
重定向与管道
简介
重定向与管道的操作过程如图:
基本命令行程序都能在屏幕上显示输出结果,称之为标准输出,文件的描述符数值为1
。同时我们也可以利用标准输出重定向保存为文件,将文件内容指定为命令的输入
输出重定向
格式: ls > [file]
>
操作会将原有的内容覆盖,如果我们需要添加内容则使用>>
输入重定向
格式: command < [file]
文件描述符
标准I/OW文件描述符类型如下:
I/O | 描述符 |
---|---|
输入 | 0 |
输出 | 1 |
错误 | 2 |
使用方法:
//将错误输出到stderr.tet 正常输出到stdout.txt
ls + 2>stderr.txt 1>stdout.txt
复制代码
管道
通常通过组合指令、连续使用指令的方法执行多个指令,此时就可以使用|
字符连接两个指令。这就是管道,表示前一命令的结果值成为下一个命令的输入。
格式: ls -l | less
高级语法
grep
基本使用
grep命令是UNIX中用于搜索的大师级工具,能够接受正则表达式和通配符。
格式: grep [格式] [文件]
grep可以多个文件进行搜索,例如: grep [格式] [文件] [文件] [文件] ...
选项 | 含义 |
---|---|
-E | 使用扩展正则表达式 |
-P | 使用Perl正则表达式 |
-o | 只输出文件中匹配到文本的部分 |
-v | 输出匹配行之外的所有行 |
-c | 统计文件或者文本中匹配的行数 |
-l | 搜索多个文件,并找出匹配文本位于哪个文件中 |
-R | 递归搜索文件 |
-i | 忽略大小写 |
-e | 匹配多个样式 |
-A | 输出匹配结果之后的几行 |
-B | 输出匹配结果之前的几行 |
-C | 输出匹配结果之前和之后的几行 |
例如:
cat data.txt
112233444
a1a1a1a1a1
bring1
pipei
44454321
grep -E "^1" data.txt
112233444
grep -E -o "^b" data.txt
b
grep -v "^b" data.txt
112233444
a1a1a1a1a1
pipei
44454321
aaa12122
grep -e "^b" -e "4$" data.txt
112233444
bring1
grep -E "^b.+1$" data.txt -A 1
bring1
pipei
grep -E "^b.+1$" data.txt -B 1
a1a1a1a1a1
bring1
grep -E -c "4$" data.txt
1
//在递归搜索所有的`.c`和`.cpp`文件
grep "title" dir2 -R --include *.{c,cpp}
//在搜索中排除所有的readme文件
grep "title" dir -R --excluds "readme"
复制代码
grep中的静默输出
在某些情况下,只需要知道一个文件是否包含指定的文本,因此通过设置grep中的-q
执行一个可以返回真假的条件测试。在静默模式中,grep命令不会向标准输入打印任何输出,仅仅是运行命令,根据命令执行成功与否返回退出的状态。
例如:
grep -q "test" file
if [ $? -eq 0 ];then
echo "包含test"
fi
复制代码
egrep
egrep是grep的扩展,可以使用其他正则表达式的元字符集,相当于grep -E
模式。