1、history
history命令与!符号有关
!! 上一条命令
!$ 上一条命令的最后一个参数
!n 执行history中的第n条命令
!字符 执行history中最近一条以指定字符开头的命令
2、通配符
和正则表达式不同,没有正则表达式强大,多用于通配文件名、路径
* 匹配0~n个字符
[abc] 匹配[]中任一字符
? 匹配1个字符
3、重定向
>filename 输出重定向 如:>filename 清空文件
>>filename 输出重定向 如:echo 'test' >>test.txt 追加test
<filename 输入重定向 如:mail -s "主题" name@qq.com <content.txt <filename相当于文件内容
2> 错误重定向 如:sh test.sh >log 2>&1,&1表示log且正常输出和异常输出不会相互覆盖
2>> 错误重定向
注意:2>&1,重定向符号前后不要有空格,否则可能会报错
4、管道
前面输出作为后边命令的输入
5、作业控制
ctrl + z 暂停
jobs 查看暂停的作业
fg n 回复指定作业
fg 恢复优先级高的,最后暂停的优先级高。类似栈,后进先出
ctrl+c 终止
6、自定义变量、全局变量、环境变量
自定义变量是在shell中直接定义的
全局变量是用export关键字声明的,可以用户当前shell及其子shell
环境变量是系统自动声明的全局变量
env 打印环境变量
set 打印全部变量
exprt 声明全局变量
unset 取消变量
bash/exit 进入/退出子shell
env | grep '^a' 打印全局变量中以a开头的
7、变量的定义
变量名由数字、字符、下下划线组成,不能以数字开头,一般不以下划线开头
变量赋值等号前后不能有空格
变量值可以不使用引号、使用单引号、双引号、反引号,在包含特殊字符时可能含义不同
不使用引号:使用[[ $a == a* ]]进行字符串通配符匹配时,可以表示模式
单引号 强制引用,引号内的特殊字符不会转义
双引号 引用,引号内的特殊字符可以转义,比如$a
反引号 引用结果,引用引号内容执行后的结果
shell中字符串可以直接连接,可以选择性使用引号引用需要进行连接的字符串
8、与环境变量相关的4个文件
| 用户登录时调用 | 进入子shell时调用 |
对任意用户有效 | /etc/profile | /etc/bashrc |
对当前用户有效 | ~/.bash_profile | ~/.bahrc |
4个文件间存在调用关系,比如profile文件经常调用bashrc文件
不同linux文件名可能不同,调用关系可能不同,甚至涉及到的不止这4个文件,可以查看具体代码确认
./bash_history 命令记录
./bash_logout 用户退出时执行
9、特殊符号
* 任意个任意字符
? 一个任意字符
[] 其中任意字符,如:[1234]
# 注释
\ 脱意,如:"\\" 输出 \\
| 管道
$ 表示变量
; 在一行写多条命令时,分隔命令
~ 家目录
& 连接命令,如:ls && cd /tmp
在后台执行命令,如:sleep 1000 &
表示输出文件,如:./test.sh 1>log 2>&1
> 重定向>> []
10、cut命令——分割
cut -d 分隔符 -f 区域 目标文件,如:cut -d ':' -f 1-3,4 /etc/passwd
cut -c 区域 目标文件,如:cut -c 1-3,4 /etc/passwd
-d:按照分隔符分割,且指定分隔符;-f:指定目标列
-c:按照字符分割,且指定目标列
11、sort命令——排序
sort -t 分隔符 -k 排序列 -nr 目标文件,如sort -t ':' -k 3 -nr /etc/passwd
-t:指定分隔符;-k指定按照第几列排序;-n指定按数字大小排序,默认按照ASCII排序;-r指定倒序排序,默认正序
sort常与cut命令结合使用,如:
sort -t ':' -k 3 -nr /etc/passwd | cut -d ':' -f 1
cut -d ':' -f 3 /etc/passwd | sort -n
遇到重复可以使用-u或者uniq -c,后者可以统计重复数量,如:
cut -d ':' -f 3 /etc/passwd | sort -n -u
cut -d ':' -f 3 /etc/passwd | sort -n | uniq -c
12、wc命令——文件内容统计
wc 目标文件,如:wc /etc/passwd
输出4个字段:行数、单词数、字符数、文件名
注意,被空白字符分割开,才会被识别为新单词;字符数包含换行符
常用wc -l 文件名,如:wc -l /etc/passwd
13、uniq -c
14、tee命令——输出
command | tee -a 输出文件,配合管道符号,将命令结果输出至标准输出的同时按照要求保存至指定文件,如:cat 1.txt | tee -a 1.log
不指定输出文件就只输出至标准输出,在命令行直接执行时,标准输出是屏幕直接打印
-a:追加,默认覆盖
与 >和>>命令的区别在于,>和>>是重定向,tee是不改变原有输出的情况下再输出一份内容
15、tr命令——替换
command | tr 原字符 新字符,配合管道符号,对命令结果进行字符替换,如:ls / | tr 'a-z' 'A-Z'
16、split命令——切割文件
split -l 行数 源文件 新文件名,文件按行数进行切割,如:split -l 10 /etc/passwd
split -b 大小 源文件 新文件名, 文件按大小进行切割,如:split -b 1M /etc/passwd
切割不会删除源文件
会自动为新文件名添加后缀,后缀貌似不能指定
17、&&和||和 ;
command1 && command2:command1成功执行后执行command2
command1 || command2:command1执行失败时执行command2
command1; command2:command1和command2的只有先后关系
18、shell中的正则
? 0个或1个问号前边的字符
+ 1个或n个加号前边的字符
* 任意个星号前边的字符
. 一个任意字符
.* 任意个任意字符
[a-zA-Z] 方括号中的字符之一
[^字符] 方括号中的字符以外
^ 以某字符开头
$ 以某字符结尾
^$ 空行
{次数} 指定次数前边的字符,在单引号表示的模式中,需要\符号转义
() 单元,将括号内作为一个整体,可以和?/+/*/{}等结合使用
| 或
[a|b] 表示a 或| 或b
? + {} () | - 这些符号在shell正则中属于扩展内容,可以使用egrep或grep -E或在模式中转义它们
19、grep命令
grep 模式 文件
显示文件中匹配模式的行,模式最好用单引号括起来
-c 统计匹配的行数
-n 显示行号
--color 高亮显示 alias grep='grep --color' 可以定义别名
-o 仅显示匹配的部分 grep -o 模式 文件 | wc -l 统计匹配次数
-v 显示不匹模式的行
-A 2 同时显示匹配行之后的两行
-B 2 同时显示匹配行之前的两行
-C 2 同时显示匹配行前两行和后两行
-r 对某目录下的文件进行grep操作,不确定是否会递归子目录下的文件
-q quite,静默模式,不输出任何结果,用于条件判断,成功匹配为真,没有成功匹配为假
两个过滤条件,可以使用管道符号grep两次
grep的输入可以是文件,也可以是重定向的内容,因此想要对字符串使用grep时,可以echo 字符串 | grep
20、sed命令:查找与替换
sed -n '特征p' 文件
打印指定行
特征可以使用 /正则模式/ 或行号,行号可以只用数字表示某一行,也可以表示某个区间如'1,10p'或'^,10'或'10,$'。使用正则时,某行含有匹配正则模式的内容,则认为该行匹配
p是print打印
-n表示静默模式,不使用-n会将全文打印,在遇到匹配特征的行时额外打印该行
sed无法显示行号和颜色,行号可以借助grep或其他命令,如:grep -n '.*' | sed '特征p' -n
当使用扩展部分的正则时,可以使用转义符号,或-r,如:sed -r '特征p' 文件 -n
sed -n -e '特征p' -e '另一个特征p' 文件 等同sed -n '特征p;另一个特征p' 文件
输出结果与使用正则中的|类似,但使用|在遇到一行匹配多个特征时,只打印一次,上边命令匹配到几个特征就重复打印几次,类似于shell命令中command1 || command2和command1;command2
p实际上是操作符,操作符除了p还有d(delete删除,删除行)
sed -r 's/模式/新字符串/g'
s表示替换;g表示遍历整行,否则每行只替换一项就开始下一行的替换;-r表示模式中扩展部分不需要转义
替换后内容不影响原内容,如果想修改原内容使用-i。也可以使用重定向,但重定向不支持重定向至自己
新字符串为空时,实际上为删除模式匹配的字符串
替换时不要使用-n选项,否则不会再屏幕上打印结果
21、awk
awk -F 分隔符 '{命令}' 文件
使用-F指定分隔符,默认分隔符为空白字符串
$0为整行,$n为分割后的第n个字符串
分割后匹配,如:awk -F ':' '$1~/root/ {print $2,$3}' /etc/passwd
单引号中的命令部分分为两部分,第一部分$1~/root/相当于if,第二部分相当于匹配成功后需要执行的命令。
使用~符号指定分割后的某个段与指定模式匹配,使用{print xxx}将需要的结果打印出来。不写{print xxx}默认为{print},即打印匹配项所在整行
替换分隔符,如:awk -F ':' '$1~/root/ {OFS="#";print $1,$2}' /etc/passwd
在条件成功后,输出时可以使用OFS指定分隔符,默认使用空格,指定分隔符时需要使用双引号,输出$0不会替换分隔符
精准匹配条件,如:awk -F ':' '$1=="root" || NR>30 {print $1,$2}' /etc/passwd
使用==表示精准匹配,注意不要写成=
可以使用||和&&表示条件的或和与
NR表示行号,和OFS类似,都是awk命令自定义的变量,另外NF表示分割后的段数
条件支持数字运算,如:awk -F ':' '$1=$3+$4 {OFS="#";print}' /etc/passwd
$3+$4后赋值给$1,使用$1进行条件判断,因为/etc/passwd的第一行运算后$1为0,所以第一行没有输出,这一点类似php,条件判断可以使用赋值语句,使用赋值后的结果进行判断。貌似仅限数字运算,字符串好像不行
$1发生变化后,$0发生变化,分隔符失效,需要重新指定分隔符,默认使用空格
22、shel脚本调试
sh -x script_name.sh
23、date
格式化字符串:
%Y 年,如:2017
%y 年,如:17
%m 月
%d 日
%H 时
%M 分
%S 秒
%w 本周第几天,如:6
%W 本年第几周,如:35
%F 完整日期,如:2017-09-02
%T 时间,如:10:25:12
%s 时间戳(秒)
格式化输出时间时,在格式化字符串前加+,如:date +'%F %T'。如果没有使用空格可以去掉引号
识别时间字符串:-d,如:date -d '2017-09-02 10:42:35'
可以相对智能的识别时间字符串,没有空白字符时可以去掉引号
使用@timestamp表示时间戳,注意时区问题
可以将识别出来的时间格式化输出
-d还可以识别时间偏移量(不知道如何对指定时间设置时间偏移量),如:date -d '+1 year'。可识别的偏移单位有year/month/day/hour/min/sec/week,偏移量可以是证书或者负数,可以多个偏移量同时出现
24、bc计算器
echo “365/7"|bc
25、变量
可以将命令直接定义为变量,使用命令时直接调用变量。
可以将命令执行结果定义为变量(反引号)
可以通过用户交互命令定义变量(read)
可以通过内置变量$0...$n,来引用当前脚本的脚本名、参数,使用$#引用参数的个数
26、read命令
在交互状态获取用户输入
read -p 提示字符串 变量1 变量2 ... 变量n
-p用于指定显示给用户的提示
定义几个变量就可以输入几个变量,输入时以空白字符隔开,多余定义变量数的输入将作为字符串赋值给最后一个变量
不定义变量可以使用$REPLY内置参数来引用输入
27、数学运算
i=1; j=2; k=$i+$j; echo $k
>1+2
因为shell中没有区分变量的类型,都是字符串,所以无法将$i+$j识别为数学运算,而是统一当做字符串连接,因此需要一些特殊的表示,告诉shell,我要做的是数学运算
方法一:$[]
i=1; j=2; k=$[$i+$j]; echo $k
>3
方法二:$(())
i=1; j=2; k=$(($i+$j)); echo $k
>3
i=1; j=2; ((k=$i+$j)); echo $k
>3
方法三:bc
以上两种不支持浮点数运算,bc可以
还不知道有什么区别
28、条件判断:if
shell中,没有布尔类型的变量,因此无法类似其他语言,将其他类型转换为布尔类型直接进行判断
有一个例外,字符“:”可以被if认为是真
shell中的条件判断语句有点复杂
数字比较判断:
在双括号中写表达式;
空格可有可无;
数字字符串会自动识别为数字。
如:
if (('1'=='1')); then echo 'true'; else echo 'false'; fi
>true
支持的操作符有:
==
!=
<
<=
>
>=
数字判断也支持在方括号中表示,但数字字符串与方括号和操作符间必须有空格,操作符需要使用对应的字符形式
如:
if [ '1' -eq '1' ]; then echo 'ok'; else echo 'not ok'; fi
>ok
相应的操作符为:
== -eq
!= -ne
< -lt
<= -le
> -gt
>= -ge
字符串比较判断:
在方括号或双方括号中写表达式;
方括号中,操作符“=”和操作符“==”等价,均为比较字符串是否匹配
双方括号仅支持操作符“==”,但支持字符串匹配和模式匹配(通配符)使用双引号时表示字符匹配,不适用双引号时表示模式匹配。如:
pattern=a*; if [[ 'ab' == $pattern ]]; then echo 'ok'; else echo 'not ok'; fi
>ok
pattern=a*; if [[ 'ab' == "$pattern" ]]; then echo 'ok'; else echo 'not ok'; fi
>not ok
字符串与方括号或双方括号或操作符间必须有空格
多个条件
可以使用“&&”操作符和“||”操作符连接完整的条件表达式,也可以使用操作符“-a”、操作符“-o”和操作符“!”在条件表达式内部对条件进行连接。
如:
num=5; if (($num>1)) && (($num<10)); then echo 'ok'; else echo 'not ok'; fi
>ok
num=5; if [ $num -gt 1 -a $num -lt 10 ]; then echo 'ok'; else echo 'not ok'; fi
>ok
一条命令也可以作为条件判断,命令执行成功为真,命令执行失败为假。因为不关心命令的输出,只关心命令是否成功执行, 所以可以将正常输出和异常输出都重定向至/dev/null,命令是否成功执行可以再命令行中通过$?查看,为0执行成功,为1执行失败。
如:
if ls /test/test/test >/dev/null 2>&1; then echo 'ok'; else echo 'not ok'; fi
>not ok
[ 1 -ne 1 ]; echo $?
>1
可以在命令行中测试条件,使用$?查看测试结果
29、exit
exit 0和exit 1都可以退出当前脚本,区别在于退出后调用$?分别返回0和1,一般认为返回0为正常结束,返回1为异常结束
30、文件判断
[ 选项 文件路径 ]
-e 文件存在
-f 文件存在且为普通文件
-d 文件存在且为目录
-r 文件存在且可读
-w 文件存在且可写
-x 文件存在且可执行
可以结合!取反
可以结合&&和||,根据条件决定后边的命令是否执行,类似if
31、exec
指定当前脚本中正常输出和异常输出的输出位置。如:
d=`date +%F`; exec >/tmp/$d.log 2>&1
以时间为文件名的日志输出
32、变量判断
[ 选项 变量 ]
-z 变量为空,如未赋值的变量,可以使用!取反
33、case循环
case 变量 in
取值1)
operation
;;
取值2|取值3)
operation
;;
*)
operation
;;
esac
匹配取值后无需退出,不会继续匹配
操作符“|”表示或
每个分支需要”;;“结尾
最后一个分支,用*匹配任意其他取值
最后需要esac结尾
33、seq
序列发生器,seq 起点 步进 终点,步进可以省略,默认为1,生成的序列,包含起点和终点
34、for循环
for i in 序列
do
operation
done
如:
for i in `seq 1 100`; do ((num+=$i));echo $num; done
数学运算中,为空的变量会被转换为0,因此未定义的变量是可以使用的
for f in `ls /etc/`; do if [ -d /etc/$f ]; then echo $f; fi; done
for i in 1 2 3 4 5; do echo $i; done
>1
>2
>3
>4
>5
可以看出来,for循环实际上是对in后边的字符串按照空白字符做了分割,上面的3个例子应该都是这个原理。注意,'1 2 3 4 5'和"1 2 3 4 5"会被作为一个整体,不会被分割。不明白使用引号的变量和不使用引号的变量到底有什么区别
因为行中可能有空白字符,因此按行输出直接for line in `cat 文件`是会出错的,可以使用sed。如:
n=`wc -l /etc/passwd|awk '{print $1}'`; for i in `seq 1 $n`; do sed -n "$i"p /etc/passwd; done
35、while循环
多用于配合操作符“:”写死循环。crontab最快1分钟循环一次,当频率需要更高时,只能用死循环
while :
do
operation
done
36、函数
input(){
echo $1
}
input liyh122
>liyh122
函数里的$n,指函数的参数,而不是脚本的参数
shell中的函数调用,直接写函数名即可,如果有参数,写在后边