一、shell基本命令回顾
1.1 查看文件和目录的命令
ls:列出目录下的清单;
cat:连接显示文件内容;
less/more:分页显示文件内容,建议使用less,相比于more更方便;
head:显示文件头部,可指定行数,默认显示10行;
tail:显示文件尾部,可指定行数,默认显示10行;
file:显示文件类型;
wc:查看文件或统计信息;
find:查找文件或目录;
1.2 操作文件和目录
touch:创建新文件(可以直接使用vim/vi/gredit等编辑器直接创建)
mkdir:创建目录,可以利用 -r选项递归创建
cp: 拷贝命令,拷贝目录时可以使用 -r 选项
ln: 创建链接命令,分为软连接和硬链接(有专门的文章介绍)
mv: 移动文件或者目录的命令,同时也是改名命令
rm: 删除命令,-r 删除目录, 谨慎使用;
1.3 管理文件或者目录的权限
ls -l : 可以列出文件和目录的权限信息;
chmod: 修改文件和目录的权限(需要了解字母及数字权限表示)
chown/chgrp: 改变属组和属主
setuid/setgid:设置用户或组权限位;
1.4 文本处理命令
sort : 文本排序
uniq : 文本去重
tr : 替换命令
grep : 查找字符串
diff : 文件对比,找出文件差异
1.5 其它常用的命令
hostname : 查看主机名
w , who : 列出系统登录的用户
uptime : 查看系统运行时间
uname : 查看系统信息
date : 显示和设置系统日期和时间
id : 显示用户属性
1.6 shell命令进阶
paster : 合并文本
dd : 备份和拷贝文件(和vim 和剪切命令一样)
tar : 打包和解包文件
mount, umount : 挂载和卸载存储介质
df : 报告文件系统磁盘空间利用率
du : 评估文件空间利用率
ps : 查看系统的进程
pidof : 列出进程的pid
top : 相当于 Linux 的任务管理器
& : 将作业后台运行
jobs : 查看作业
bg : 让挂起的进程在后台继续执行
fg : 将后台进程放入前台
fdisk: 查看系统的磁盘信息
举例:
前后台切换演示:
解释: 先执行 sleep 100 & 让这个进程在后台执行,然后我们先使用 ps 配合 grep 命令查看一下 sleep 进程的信息,接着 jobs 查看一下后台运行的作业, 使用 fg 命令使其继续在前台执行,我们可以看到显示了sleep 100 , 接着我们又不想让他继续执行了,使用 ctrl + z 使其挂起,我们用jobs查看,可以看出其处于 stopped 状态,接着使用 bg 命令使其继续在后台执行,查看状态, 处于running状态;
二、 shell基本语法学习
2.1 shell 编程基础
1)基本格式
#!/bin/bash
echo "hello world"
分析:还是 hello world 起步,第一行的 #!叫做 Shebang, 然后后面的 /bin/bash 则是指定解释器,既然shell是门解释性语言,自然需要解释器,类似的,如果是 python脚本,则是 #!/bin/python 可能还需要一些编码格式的规定(utf - 8),如果没有指定解释器,默认选择 sh ; 同时还需要给文件可执行权限,否则会报错,虽然我们一般把shell 脚本文件命名为 .sh 的文件(在Linux中文件后缀只能起到标识的作用,没有实际意义);
2)shell 中的注释,在shell中注释的符号是 “#”;
3)shell的变量
-
在shell中设置变量和平时在命令行设置变量是一样的,可以直接定义一个变量,例如: a=10 不需要声明类型,不需要分号;
-
如果需要明确指定变量的类型的话,可以只用declare的选项指定类型;
-
变量的作用域:在shell 中,变量默认都具有全局属性,如果需要局部的变量则需要在变量的声明处加 local 关键字。如: local a=10
-
变量的操作:
-
获取变量的值在命令行获取变量的值是通过
echo ${a}
打印变量的值到终端的,那么echo的作用是打印,’${}'的作用不言而喻(花括号可省略,起分割的作用)。 -
变量的运算
let a+=1,即使用 let 命令,当然除了 let 命令还有 ‘(())’ 双括号,都可以进行变量的运算; -
参数变量
说到shell的参数,有两个点,一个是命令行参数,一个是函数的参数,这里先说明命令行参数,函数的参数在后面学习函数的时候补充;
-
-
变量说明:
$$ Shell本身的PID(ProcessID)
$! Shell最后运行的后台Process的PID
$? 最后运行的命令的结束代码(返回值)
$- 使用Set命令设定的Flag一览
$* 所有参数列表。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。
$@ 所有参数列表。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。
$# 添加到Shell的参数个数
$0 Shell本身的文件名
$1~$n 添加到Shell的各参数值。$1是第1参数、$2是第2参数…
例子:
注:取消变量的定义 unset
4) shell环境变量和普通变量
首先,明确两点,第一点即环境变量和普通变量在虚拟地址空间的存放位置,环境变量在栈顶的位置(高地址处),而普通变量是在数据段存放的;第二点,子进程会继承父进程的环境变量;
普通变量的命令行声明: a=10
将普通变量变为环境变量:export a
如何验证?
1、在父bash 中声明变量 a=10, 命令行敲 ‘bash’ 命令相当于起了一个子bash, 在子 bash 中查找是否有 a变量;
(set 命令查看所有变量, env 命令查看所有环境变量,exit或者ctrl + d 退出子bash)
2、在父bash 中将变量 a 声明为环境变量 ‘export a’, 在子bash 中查看变量 a;
2.2 if条件执行
shell的条件执行其实和C差不多,具体的差异就在于语法格式的一些差别;
不同于C的是,bash的条件测试不单单只是可以通过if进行判断,还要结合一些特殊的符号,命令和参数;
先列出基本的if语句的使用格式:
if true
then
echo "hello world!"
else
echo "see you world!"
fi
这就是 if 语句的基本使用格式,当然,中间还可以有‘elif’相当于 C 的 else if ; 值得注意的是开始的 then和最后的 fi , 每个 if 都必须有一个fi 与之对应代表结束,因为没有了 ‘{}’;
前面说了,shell的条件判断需要结合一些命令,符号,选项来配合使用;
‘[]’ 和 test 都被用作测试,如:
if [ -f install.log ]
then
echo "hello"
fi
test -f install.log; echo "hello"
‘[ ]’ 和 test 有很多选项,这里我就不一一演示,需要的话直接 man test; ( 注意: 使用 ‘[ ]’ 时, 需要两个空格,‘[’的后面, ‘]’的前面各一个);
不但这些,还有比较的符号,其中又分字符串和算数的不同;
字符串:
选 项 | 作 用 |
---|---|
-z str | 判断字符串 str 是否为空。 |
-n str | 判断宇符串 str 是否为非空。 |
str1 = str2 或 str1 == str2 | =和==是等价的,都用来判断 str1 是否和 str2 相等。 |
str1 != str2 | 判断 str1 是否和 str2 不相等。 |
str1 > str2 | 判断 str1 是否大于 str2。>是>的转义字符,这样写是为了防止>被误认为成重定向运算符。 |
str1 < str2 | 判断 str1 是否小于 str2。同样,<也是转义字符。 |
算术:
操作符 | 描述 |
---|---|
< INTEGER1 > -eq < INTEGER2 > | 如果< INTEGER1 >与< INTEGER2 >相等则为真 |
< INTEGER1 > -ne < INTEGER2 > | 如果< INTEGER1 >与< INTEGER2 >不相等则为真 |
< INTEGER1 > -le < INTEGER2 > | 如果< INTEGER1 >小于或等于< INTEGER2 >则为真 |
< INTEGER1 > -ge < INTEGER2 > | 如果< INTEGER1 >大于或等于< INTEGER2 >则为真 |
< INTEGER1 > -lt < INTEGER2 > | 如果< INTEGER1 >小于< INTEGER2 >则为真 |
< INTEGER1 > -gt< INTEGER2 > | 如果< INTEGER1 >大于< INTEGER2 >则为真 |
追加一个知识点: 因为字符串的比较使用 ‘[]’ 时需要对 ><进行转义,所以shell提供 ’ [[ ]] ’ 符号,则不再需要转义,对于算术,shell提供 ’ (( )) ’ 则可以直接使用比较符进行比较;
2.3 &&和||
- && : &&符号的前面的表达式为真才会执行 &&后面的表达式;
- || : || 符号前面的表达式为假才会执行 || 后面的表达式;
- ‘!’: 逻辑非
通常 && 和 || 配合使用,如:
2.4 shell 的 case 语句
shell的case语句的格式如下:
case $1 in
1)
echo "1"
;;
2)
echo "2"
;;
esac
上面就是case语句的格式,这里刚好提醒一点,就是在shell中,不允许出现空语句,如果非要有空语句,则必须写上一个 冒号‘:’;
2.5 bash 循环
shell的循环:for/while/until,下面只演示前两种,until不太用到;
for循环
for i in $(seq 10)
do
echo -n $i
done
#类C 的for 循环:
for (( i=0; i<10; ++i ))
do
echo -n $i
done
注: seq 是生成连续序列的命令,而shell中执行命令的话,会用 ‘$()’;
echo -n 选项则是取消换行,每个echo语句都会带一个换行,直接一个echo则代表换行;
while循环
值得一提的是break和continue关键字在shell中依然有效;
i=1
while true
do
if [ $i -gt 2 ];then
echo $i
break
fi
let i++
done
continue语句不做演示;
2.6 shell的函数
首先,shell函数的定义:
function fun()
{
if [ $# -ne 2 ];then
return 1
fi
local a=$1
local b=$2
let c = a + b
echo "hello $c"
return 0
}
fun 1 2
if [ $? -ne 0 ];then
echo "arguments fault!"
exit
else
echo "used right"
fi
上面就是一个简单的脚本,起作用是调用一个fun函数,判断调用是否正确;
分析: 从这个脚本中我们可以看出shell脚本函数的使用方式,从定义到参数的获取,再到返回值;最后还有函数的调用方式其实和命令的执行方式是一样的;
(注: function关键字可以省略但不建议,return 可以返回的值是 0-255)
额外知识点: 在shell脚本中 双引号 和 单引号是有区别的,虽然在大部分场景中它们是一致的,但是如果含有特殊字符的话,双引号是没有对特殊字符进行转义的,所以上面的脚本中 “hello $c”可以顺利执行,但是单引号的话默认会对特殊字符转义的,例如:
2.7 shell 重定向
说起重定向,估计不少同学都想到了管道;
但是,管道并不是重定向,重定向是将一个命令的输出结果作为下一个命令的输入,而重定向是将输出和文件相链接的;
重定向分为输入重定向和输出重定向,其中又有追加和覆盖的区别,总的来说就是下面四个符号:
’ > ‘, ’ >> ‘, ’ << ’ , ’ < ‘;
举例来说:
当然,不仅可以这样,还可以将标准错误也重定向到文件;
ls l 2>test.sh
输入重定向:
注: 这里的END不是固定的,只是起一个标签的作用,代表下次遇到END就结束输入;
重定向的这种用法还被用到项目中的configure文件,使configure文件可以自动生成Makefile文件,例如:
2.8 shell 脚本从标准输入读取
这个其实只是一个read的使用,在shell中使用read从标准输入读取数据;
例如:
#! /bin/bash
read -p "login name:" name
read -p "passwd:" passwd
read -p "display information? [y/n]" choose
if [ $choose = 'y' ];then
echo $name
echo $passwd
fi
结果:
三、sed/awk工具
3.1 sed
sed是一行一行处理文本的,还有需要知道sed有一个HOLD空间和模式空间,HOLD用来作为文档处理的暂存空间,不能有任何的操作,所有的操作只能在模式空间进行;
sed常用的选项:
-e : 它告诉sed将下一个参数解释为sed指令,即需要连续多个处理时使用;
-f : 指定由sed指令组成的脚本的名称;
-i : 直接在读取的内容进行修改,如果没有—i,不会源文件造成任何修改;
-n : 静默模式,即只输出匹配的行,如果没有-n则匹配行会和源文件全部输出;
sed的编辑命令有24个之多,在这里只学习常用的几个:
追加(a),更改(c),删除(d),插入(i),替换(s),打印(l),打印行号(=),转换(y);
例子:
下面这些选项则是需要用到暂存空间时要用到的选项:
+ g:[address[,address]]g 将hold space中的内容拷⻉贝到pattern space中,原来pattern space里的内容清除
+ G:[address[,address]]G 将hold space中的内容append到pattern space\n后
+ h:[address[,address]]h 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
+ H:[address[,address]]H 将pattern space中的内容append hold space\n后
+ d:[address[,address]]d 删除pattern中的所有行,并读入下一新行到pattern中
+ D:[address[,address]]D 删除multiline pattern中的第一行,不读入下一行
+ N,添加下一行至pattern space内;
+ x:交换保持空间和模式空间的内容
求1~100的和
两种方式:
分析:第一个例子利用了暂存空间和模式空间的特点进行求和,其中 $ 代表最后一行; ‘^’ 代表第一行; 然后利用选项H 和 x; 其中利用sed的s编辑命令和正则表达式把换行换为加号,最后通过管道把表达式交给bc计算器,得到最终结果;
第二个例子则是利用sed的标签,没有用到暂存空间; 其中 :a是设置了一个 a标签, ba的作用是跳转到a标签;
3.2 awk工具
既然有了sed为什么还要有awk呢? 肯定是因为awk比sed更加强大,就最明显的一点,sed只能一行一行处理数据,不能处理一列一列的数据,而awk就可以做到,而且awk还可以利用类C的语法结构,简直强大;
找出你在Linux上最常用的十个命令:
history | awk ‘{print $1}’ | sort | uniq -c | sort -nr |head
awk 的默认的列分割符是空格,我们也可以指定分割符,利用 -F选项;
例如:
`awk 还有一个特点就是它的 BEGIN 块和 END 块;
BEGIN块的作用是在awk执行匹配之前先执行的语句,END自然就是awk处理完之后执行的语句;
例如: