文章目录
Shell概述
什么是Shell
Shell俗称壳(用来区别于核),是一个命令解析器,它接收用户的命令(ls、mkdir…),然后调用相应的应用程序。
Shell的种类
流行的shell有bash、sh、csh、tcsh、ksh、zsh等,不同的shell具备不同的功能。
- bash
是Linux中默认的shell,特点是可以通过help命令来查看帮助,包含的功能几乎涵盖其余Shell所具有的功能。 - sh
是一个快捷方式,已经被/bin/bash所取代 - csh
使用的是“类C”语法,具有C语言风格。其内部命令有52个,较为庞大。目前使用的并不多,已经被/bin/tcsh所取代。 - tcsh
是csh的增强版,与C shell完全兼容。 - ksh
语法与bash相同,同时具备了C shell的易用特点。它有42条内部命令。许多安装脚本都使用,与bash相比有一定的限制性。 - zsh
是目前Linux里最庞大的一种,使用起来也比较复杂。它有84个内部命令。一般情况下,不会使用该shell。
Shell中的变量
变量的读取
- ①命令 echo ${变量}
- ②省略{},命令 echo $变量
变量的设置
变量名:只能是英文字母、数字、下划线,但开头不能是数字。通常大写为系统默认变量,用户定义可以使用小写,方便区分。
变量值:值中有空格,可以使用双引号或单引号将其连接起来,
双引号中的内容保持其原本特性,如 lang=“lang is $LANG” ,echo $lang 输出是lang is en_US.UTF-8
单引号中的内容仅为一般字符,如lang =‘lang is $LANG’ ,echo $lang 输出是lang is $LANG
值中有特殊字符,可以使用“\”转义字符将$、!、\转为一般字符
- ① export 变量名=变量值 ,=号两边不能直接跟空格
- ②变量名=变量值
- ③把一个命令定义为一个变量
- 使用反`(Tab上面,1左面的键)
- 使用$(命令)
- 使用反`(Tab上面,1左面的键)
取消变量
命令 unset 变量名
如果取消系统变量,需要修改/etc/profie 文件,否则重启依然存在
变量的生命周期
全局变量:上面方法定义变量就是
局部变量:函数脚本中的变量通常使用local 修饰,local 变量1 ,表示变量1 只能在函数内部使用
数据重定向
将命令执行后应该出现在屏幕上的数据,传输到其他的地方,例如文件、其他命令。
数据种类
命令执行后出现在屏幕上的数据分为:
- 标准输出
- 标准错误输出
用法
- 标准输出:编号1
- 标准错误输出:编号2
命令 1> :以覆盖的方法,将正确的数据输出到文件
命令 1>>:以追加的方法,将正确的数据输出到文件
命令 2>:以覆盖的方法,将错误输出的数据输出到文件
命令 2>>:以追加的方法,将错误输出的数据输出到文件
命令执行判断
命令执行成功与否的判断,是根据命令执行回传值($?)自动进行判断。分为:
与&&
命令1&&命令2
- 若命令1执行成功 (echo $? 返回=0),则开始执行命令2
示例:ls 成功,接着执行pwd,如下图:
- 若命令1执行失败 (echo $? 返回!=0),则不再执行命令2
示例:ls失败,没有再执行pwd,如下图:
或||
命令1||命令2
- 若命令1执行成功 (echo $? 返回=0),则不再执行命令2
示例:ls成功,没有再执行pwd - 若命令1执行失败 (echo $? 返回!=0),则开始执行命令2
示例:ls失败,接着执行pwd ,如下图:
管道命令
利用管道符“|”将两个命令隔开,管道左边命令的输出就会做为管道右边命令的输入
连续使用管道符“|”,意味着第一个命令的输出将作为第二个命令的输入,第二个命令的输出将作为第三个命令的输入。由于实际使用不多,易出错,不建议使用。
find
在一个目录中搜索文件(包含其子目录),可以指定一些匹配条件,如按文件名、文件类型、用户及时间戳来查找文件
用法
find [path] [-option] 参数
-
path:find命令查找的目录路径。可以使用绝对路径,也可以使用相对路径,当前目录可以省略。
-
-option:find命令的匹配条件类型
按照文件名 -name 文件全名/*结尾
示例:查找文件 cert8.db,如下图:
示例:查找文件 *.db,如下图:
按照文件大小 -size
示例:等于0字节的文件,如下图:
示例:大于100000字节的文件,如下图:
按照权限类型 -perm
按照所属用户 -user
按照文件更改有效时间 -mtime
- -mtime -n 更改时间距离现在n天以内
- -mtime +n 更改时间距离现在n天以前
按照文件类型 -type
-
d 目录
-
f 普通文件
-p 管道连接文件(是连接某些读/写进程的共享文件)
-
b 块设备文件(操作系统级别的定义)
-
c 字符设备文件(相对于b)
-
l 符号连接文件(类似于Windows的快捷方式)
结语
find常用命令就这些,不常用的命令(如 -nogroup 没有在用户组的文件)就不再赘述。
grep
是一种强大的文本搜索工具,可以使用正则表达式搜索文本,将匹配行打印出来。
用法
grep [option] parttern filename
省略option
-b 打印匹配行前添加该行第一个字符的编码
-c 只打印匹配的行数,不打印匹配的文本
-h 当搜索多个文件时,不显示文件名前缀
显示前缀
不显示前缀
-i 匹配时忽略大小写差别
-q 只返回退出状态,不输出内容
-f 模板文件 目标文件 以模板文件每一行作规则样式,去查找目标文件
-n 显示匹配行的前后n个不匹配行
-n 输出行号
总语
grep命令常用的选项已经说完,如果你在使用时想使用更多的选项可以去搜索查看。
tail
tail 命令可用于查看文件的内容,有一个常用的参数 -f 常用于查阅正在改变的日志文件。 会把文件最尾部的内容显示在屏幕上,并且不断刷新,只要文件更新就可以看到最新的文件内容。
用法
tail [参数] [文件]
tail -f 文件名
tail -n Number 文件名 ,显示文件最后Number行
tail -n +Number 文件名,显示文件第Number行之后
结语
一般情况,日志文件增长的特别快,人的眼镜根本来不及阅读。有了tail命令,就可以很方便的观察日志了。
sort
sort命令用于将文本文件内容以行为单位来排序。
用法
sort [OPTION]... [FILE]...
无OPTION
-c 检查文件是否已经按照顺序排序。
-r 以相反的顺序
-M将前面3个字母依照月份的缩写进行排序
-n依照数值的大小排序
-o<输出文件> 将排序后的结果存入指定的文件
结语
sort命令比较简单,这就讲完了。
sed
定义
sed是非交互式文本工具,相对于vim交互式文本工具。
处理过程
- 将当前正在处理的行保存到一个临时缓冲区(模式空间)
- 处理临时缓冲区的行,并发送到屏幕上
- 删除临时缓冲区的行,将文本中下一行保存到临时缓冲区
- 处理临时缓冲区的行,即②步
- 处理完文件最后一行,sed结束运行
用法
sed [option] "action" [file]
option
- -n仅显示script处理后的结果
- -e 允许对输入数据应用多条sed命令进行编辑
- -f直接将sed的命令写在一个文件中,-f filename就可以运行文件中sed动作
action
- s 字符串匹配/查找
- i 编辑
- d删除
- a追加
- c替换
- p打印指定的输出行
例子
将文件每行的LINUX替换为World, 命令
- 成功替换,并且原文件没有改变
sed "s/LINUX/world/g" sed.txt
g的含义是整行都替换,如果是数字代变第几个匹配替换
- 第一个匹配
sed "s/LINUX/world/1" sed.txt
- 匹配的个数不够就不替换
sed "s/LINUX/world/3" sed.txt
s前面加数字,表示第几行匹配替换
- 只第一行匹配
sed "1s/LINUX/WORLD/1" sed2.txt
- 第二行匹配失败,不会再去下一行匹配替换
sed "2s/LINUX/WORLD/1" sed2.txt
- 1行-4行替换
sed '1,4s/LINUX/WORLD/g' sed2.txt
- 多个action以“;”分隔
sed "4s/LINUX/WORLD/1;4s/LINUX/WORLD/2" sed2.txt
sed -e '4s/LINUX/WORLD/1' -e '4s/LINUX/WORLD/2' sed2.txt
直接替换原文件中内容
sed -i "s/LINUX/WORLD/g" sed2.txt
在第一行插入
sed '1i hello world ' sed2.txt
在第一行追加
sed '1 a hello world ' sed2.txt
删除匹配行
sed '/aa/d' sed2.txt
结语
如果你有一个 100 万行的文件,你要在第 100 行加某些文字,此时使用 vim 可能会疯掉!因为文件太大了!那怎办?就利用 sed 啊!透过 sed 直接修改/取代的功能,你甚至不需要使用 vim 去修订!
cut
cut命令用于剪切每行的数据。
用法
cut [-option] filename
option
-
-b 字节
-
-c 字符
-
-d按指定分隔符分隔列
-
-f提取第几列 与-d一起使用
例子
剪切6-10 个字节
cut -b 6-10 cut.txt
剪切第5个字节以后
cut -b 5- cut2.txt
剪切到8个字节以后
cut -b -8 cut2.txt
剪切1-4个字节
cut -c 1-4 cut2.txt
以‘-’分割,取第2列
cut -d - -f 2 cut.txt
结语
cut命令是按照行进行剪切,这种机制跟sed有点类似,可以方便的处理大文件。
history
介绍
系统会记录一定数量的命令,使用history命令可以快速查找到之前使用过的某个历史命令,并快速运行这条命令。用好history命令可以大大提高工作效率,比如在一台Ubuntu电脑上安装了一些软件,就可以用history命令将软件安装配置过程中用到的所有命令保存下来,保存到一个脚本中,就可以在其他Ubuntu电脑上运行该脚本安装相同的软件。
用法
- 显示全部历史
history
- 显示最近5条命令
history 5
- 使用上下箭头(“↑”、“↓”)查找历史命令
向上 2次
向下 1次
- !! 运行上一条命令
!!
- !num运行第几条命令
!1027
- !num 参数 运行第几条命令,后面跟上参数
!1036 /root
- !命令 运行上一条命令
!ls
- !ls:s/匹配的字符/替换后字符
!ls:s/root//
- fc 编辑并运行上一个命令
fc
进入编辑页面,默认文本是上一条命令
将上一个命令编辑为 ls /root ,wq! 报存退出,命令执行
- fc num 编辑并运行第num个命令
fc 1055
进入编辑页面,默认是1055条命令
将上一个命令编辑为 history 2 ,wq! 报存退出,命令执行
- 按下“ctrl”+"r"键,迅速输入命令包含的字符,搜索命令
按下“ctrl”+“r”,输入s
接着按“ctrl”+“r”,相当于搜索下一个
- history -c 清空历史命令
history -c
结语
History命令的用途确实很大,可需要小心安全的问题。尤其是 root 的历史纪录档案,这是黑客们的最爱。因为不小心的 root 会将很多的重要资料在执行的过程中会被纪录在 ~/.bash_history 当中,如果这个档案被解析的话,后果不堪设想。
script
按装一个软件时候,通常需要下载源码包,编译,下载依赖,最后花费很多时间。如果有很多台机器需要安装同一个软件的话,那是十分不方便。
要想让所有这些事情变得简单并且自动化,我们可以使用shell脚本。
第一个script
#!/bin/bash
echo "Phone number ?"
#有个read命令用来接收用户的回答
read phone
echo "You have entered $phone as a phone number"
exit 0
- 第一行 #!/bin/bash,告述系统使用什么脚本
- 除了第一行的#都是注释
- read 后面直接跟变量名,如果是read -p,后面跟 “你的手机:”phone
- $phone ,是获取phone变量的值
- exit 0 以0作为该脚本的执行返回值。执行正常返回0,可以通过$?获取返回结果。centoOS-6.5 以上已经兼容返回值,不写也可以得到返回值0。
运行脚本
- 方式一、使用bash前缀运行
bash filename
- 方式二、将脚本文件转为可执行文件
chmod +x filename
- 方式三、使用source前缀执行
source filename
存在一个bug,遇到exit 会直接退出登录
结语
shell脚本语言就跟和几个人聊天类似。你只需把所有命令想象成能帮你做事的那些人,只要你用正确的方式来请求他们去做。
比如说,你想要写文档。首先,你需要纸。然后,你需要把内容说给某个人听,让他帮你写。最后,你想要把它存放到某个地方。或者说,你想要造一所房子,因而你需要请合适的人来清空场地。在他们说"事情干完了",那么另外一些工程师就可以帮你来砌墙。最后,当这些工程师们也告诉你"事情干完了"的时候,你就可以叫油漆工来给房子粉饰了。
test
用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。
用法
判断某个文件类型
- -e 该文件是否存在
- -f 该文件名是否存在,且为文件
- -d该文件名是否存在,且为目录
- -b该文件名是否存在,且为块文件
- -c该文件名是否存在,且为字符文件
- -S该文件名是否存在,且为Socket文件
- -p该文件名是否存在,且为PIPO(管道)文件
- -L该文件名是否存在,且为链接(类似快捷方式)文件
判断某个文件权限
- -r该文件名是否存在,且具有可读权限
- -w该文件名是否存在,且具有可写权限
- -x该文件名是否存在,且具有可执行权限
- -s该文件名是否存在,且为非空文件
- -u该文件名是否存在,且具SUID的属性
- -g该文件名是否存在,且具有SGID的属性
判断字符串
- -z 判断字符串是否为空,空返回true
- -n 判断字符串是否为非空,空返回false
- str1=str2/str1==str2 判断str1是否等于str2,相等返回true
- str1!=str2 判断str1是否不等于str2,相等返回false
两个文件之间比较
- -nt 判断 file1 是否比 file2 新
- -ot判断 file1 是否比 file2 旧
- -ef判断 判断两个文件是否为同一个文件
demo
#!/bin/bash
echo "请输入文件名,我会判断是否存在!"
read -p "现在请输入一个文件名:" filename
#1、判断用户是否输入文件名
test -z $filename && echo "请输入一个字符串!否则程序无法继续"&&exit 1
#2、判断用户输入的文件名是否存在!
test ! -e $filename && echo "输入的文件名不存在!"&& exit 1
#3、判断用户输入文件名是什么类型文件
test -f $filename && filetype="文件"
test -d $filename && filetype="目录"
test -r $filename && perm="读"
test -w $filename && perm=${perm},"写"
test -x $filename && perm=${perm},"执行"
#4、打印用户输入的文件名的类型和权限
echo "输入的文件名$filename是一个$filetype,它的权限是$perm"
exit 0
结语
test命令介绍就到这里了,你可能看过后一段时间就忘了,不用╮(╯﹏╰)╭,用的时候再来翻看。
判断符号[]
基本和test相同
用法
[ ] 中内容要与中括号保持一个空格
错误代码 #!/bin/bash
['a'=='b' ] && echo 'hello'
== 和 !=用于比较字符串,字符串要与==、!=保持一个空格
#!/bin/bash
[ 1 -eq 2 ] && echo '1==2'
[ 1 -le 2 ] && echo '1<=2'
整数比较只能使用 -eq(=),-gt(>),-ge(>=),-lt(<),-le(<=)这种形式
#!/bin/bash
[ 1 -eq 2 ] && echo '1==2'
[ 1 -le 2 ] && echo '1<=2'
[]中的逻辑与和逻辑或使用-a(&&)和-o(||)表示
#!/bin/bash
[ 'a' == 'b' -o 'a' != 'b' ] && echo 'a==b || a!-b is true'
结语
判断符号[]到这里就结束了,使用时候需要注意每个元素[]、==、!=、-eq、-ge、-gt。。。都要隔一个空格。
参数
在执行 Shell 脚本时,向脚本传递的参数。形如bash test.sh arg1 arg2 arg3 arg4
获取参数
$n 获取传入脚本的第n个参数,$0代表脚本程序文件名,$1、$2代表第一个参数,第二个参数
#!/bin/bash
echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
$#代表参数的个数
#!/bin/bash
echo "Shell 传递参数个数:$#";
$*代表每个变量使用双引号括起来,以空格隔开,类似 “$1 $2 $3 $4”
#!/bin/bash
echo "Shell 传递参数:$*";
$@所有参数用一个双引号括起来,参数中间空格隔开 ,类似"$1" “$2” “$3” “$4”
#!/bin/bash
echo "Shell 传递参数:$@";
shift 变量偏移
#!/bin/bash
echo "Shell 传递参数个数:$#";
echo "Shell 传递参数是:$@"
shift
echo "Shell 传递参数个数:$#";
echo "Shell 传递参数是:$@"
结语
script参数就是这些了,其实常用的命令ls -a -l 内部也是类似的。
条件判断
分支结构的一种。
语法
if [ 条件判断 ]
then
//命令
fi
或
if [ 条件判断 ]; then
//条件成立执行,命令
fi
[]中条件判断
整数判断
- -eq:相等
- -ne:不等于
- -gt:大于
- -ge:大于或等于
- -lt:小于
- -le:小于或等于
#!/bin/bash
a=10
b=13
if [ $a -gt $b ];then
echo "$a>$b"
fi
if [ $a -le $b ]
then
echo "$a<=$b"
fi
其他判断
参见 判断符号[]
多分支结构
if [ 条件1 ]; then
//条件1成立,执行指令集1
elif [ 条件2 ];then
条件2成立,执行指令集2
else
条件都不成立,执行指令集3
fi
demo
#!/bin/bash
a=13
b=13
if [ $a -gt $b ];then
echo "$a>$b"
elif [ $a -lt $b ];then
echo '$a<$b'
else
echo '$a==$b'
fi
结语
script中的if条件判断就这些,看起来和java中的if结构类似,只是语法不同。
函数
可以将一段相同用途的脚步封装成函数,方便多处直接调用。
语句
function name() {
命令
}
或
(function) name() {
命令
}
demo
#!/bin/bash
function print(){
echo "hello $1"
}
print "Lili"
print "Lucy"
结语
script中函数定义后,就可以直接当成script命令一样使用。
case
case语句使用于需要进行多重分支的应用情况。
语法
case $变量 in "值1")
程序段1
;;
"值2")
程序段2
;;
*)
exit 1
;;
esac
- $变量 相当于java中switch(变量)
- “值n”) 相当于java中的case n:
- ;;相当于java中break
demo
#!/bin/bash
read -p "请输入一个小于9的数:" a
case $a in 1)
echo "1"
;;
2)
echo "2"
;;
[3-9])
echo "$a"
;;
*)
echo "请输入一个小于9的数:"
exit 1
;;
esac
循环语句
概述
循环可以不断的执行某个程序段落,直到用户设置的条件达成为止,称为不定循环,如while、until。
已经固定要运行多少次的循环,称为固定循环,如for。
while
while循环条件为“假”时结束
语法
while [ condition ] ; do
命令
done
或
while [ condition ]
do
命令
done
案例
每隔2秒打印下系统负载情况
#!/bin/bash
while true
do
uptime
sleep 2
done
计算1+2+3…+100的和并输出
#!/bin/bash
sum=0
i=1
while [ $i -le 100 ]
do
sum=$(($sum+$i)) #$($sum+$i) 取的是 $sum的值+i的值,没有这个变量
i=$(($i+1)) #同上,运算结果给变量赋值需要使用$((...))
done
echo "the result of '1+2+3+...+100' is $sum"
until
与while相反,循环条件为“真”结束。
语法
until [ condition ] ; do
命令
done
或
until [ condition ]
do
命令
done
案例
计算0-5的幂方
#!/bin/bash
i=0
until [ $i -gt 5 ] #大于5
do
let square=i*i #let简单的计算器, BASH中用于计算的工具
echo "$i*$i = $square"
let i++
done
for
语法
for 变量名 in 变量取值列表
do
命令
done
案例
列出变量列表中所有元素
#!/bin/bash
for num in 5 4 3 2 1
do
echo $num
done
获取目录下的文件名作为变量列表打印输出
#!/bin/bash
for ls in `ls`
do
echo $ls
done
结语
循环里的while相比较java中的while,until和java中的do-while相比较,for和java中的for相比较,是不是看起来就很简单了