## 本文参考
[菜鸟shell教程](https://www.runoob.com/linux/linux-shell.html) [linux环境配置](https://www.cnblogs.com/youyoui/p/10680329.html)
## linux目录结构
| 目录 | 应放置档案内容 |
| ------ | ------------------------------------------------------------ |
| /bin | 系统有很多放置执行档的目录,但/bin比较特殊。因为/bin放置的是在单人维护模式下还能够被操作的指令。在/bin底下的指令可以被root与一般帐号所使用,主要有:cat,chmod(修改权限), chown, date, mv, mkdir, cp, bash等等常用的指令。 |
| /boot | 主要放置开机会使用到的档案,包括Linux核心档案以及开机选单与开机所需设定档等等。Linux kernel常用的档名为:vmlinuz ,如果使用的是grub这个开机管理程式,则还会存在/boot/grub/这个目录。 |
| /dev | 在Linux系统上,任何装置与周边设备都是以档案的型态存在于这个目录当中。 只要通过存取这个目录下的某个档案,就等于存取某个装置。比要重要的档案有/dev/null, /dev/zero, /dev/tty , /dev/lp*, / dev/hd*, /dev/sd*等等 |
| /etc | 系统主要的设定档几乎都放置在这个目录内,例如人员的帐号密码档、各种服务的启始档等等。 一般来说,这个目录下的各档案属性是可以让一般使用者查阅的,但是只有root有权力修改。 FHS建议不要放置可执行档(binary)在这个目录中。 比较重要的档案有:/etc/inittab, /etc/init.d/, /etc/modprobe.conf, /etc/X11/, /etc/fstab, /etc/sysconfig/等等。 另外,其下重要的目录有:/etc/init.d/ :所有服务的预设启动script都是放在这里的,例如要启动或者关闭iptables的话: /etc/init.d/iptables start、/etc/init.d/ iptables stop/etc/xinetd.d/ :这就是所谓的super daemon管理的各项服务的设定档目录。 /etc/X11/ :与X Window有关的各种设定档都在这里,尤其是xorg.conf或XF86Config这两个X Server的设定档。 |
| /home | 这是系统预设的使用者家目录(home directory)。 在你新增一个一般使用者帐号时,预设的使用者家目录都会规范到这里来。比较重要的是,家目录有两种代号: ~ :代表当前使用者的家目录,而 ~guest:则代表用户名为guest的家目录。 |
| /lib | 系统的函式库非常的多,而/lib放置的则是在开机时会用到的函式库,以及在/bin或/sbin底下的指令会呼叫的函式库而已 。 什么是函式库呢?你可以将他想成是外挂,某些指令必须要有这些外挂才能够顺利完成程式的执行之意。 尤其重要的是/lib/modules/这个目录,因为该目录会放置核心相关的模组(驱动程式)。 |
| /media | media是媒体的英文,顾名思义,这个/media底下放置的就是可移除的装置。 包括软碟、光碟、DVD等等装置都暂时挂载于此。 常见的档名有:/media/floppy, /media/cdrom等等。 |
| /mnt | 如果妳想要暂时挂载某些额外的装置,一般建议妳可以放置到这个目录中。在古早时候,这个目录的用途与/media相同啦。 只是有了/media之后,这个目录就用来暂时挂载用了。 |
| /opt | 这个是给第三方软件放置的目录 。 什么是第三方软件啊?举例来说,KDE这个桌面管理系统是一个独立的软件,不过他可以安装到Linux系统中,因此KDE的软件就建议放置到此目录下了。 另外,如果妳想要自行安装额外的软体(非原本的distribution提供的),那么也能够将你的软体安装到这里来。 不过,以前的Linux系统中,我们还是习惯放置在/usr/local目录下。 |
| /root | 系统管理员(root)的家目录。 之所以放在这里,是因为如果进入单人维护模式而仅挂载根目录时,该目录就能够拥有root的家目录,所以我们会希望root的家目录与根目录放置在同一个分区中。 |
| /sbin | Linux有非常多指令是用来设定系统环境的,这些指令只有root才能够利用来设定系统,其他使用者最多只能用来查询而已。放在/sbin底下的为开机过程中所需要的,里面包括了开机、修复、还原系统所需要的指令。至于某些服务器软件,一般则放置到/usr/sbin/当中。至于本机自行安装的软件所产生的系统执行档(system binary),则放置到/usr/local/sbin/当中了。常见的指令包括:fdisk, fsck, ifconfig, init, mkfs等等。 |
| /srv | srv可以视为service的缩写,是一些网路服务启动之后,这些服务所需要取用的资料目录。 常见的服务例如WWW, FTP等等。 举例来说,WWW伺服器需要的网页资料就可以放置在/srv/www/里面,看来平时我们编写的代码应该放到这里了。 |
| /tmp | 这是让一般使用者或者是正在执行的程序暂时放置档案的地方。这个目录是任何人都能够存取的,所以你需要定期的清理一下。当然,重要资料不可放置在此目录啊。 因为FHS甚至建议在开机时,应该要将/tmp下的资料都删除。 |
### /dev文件夹
#### /dev/null与/dev/zero详解
在类Unix系统(包括Linux)中,
/dev/null 它是空设备,也称为位桶(bit bucket)或者黑洞(black hole)。你可以向它输入任何数据,但任何写入它的数据都会被抛弃。通常用于处理不需要的输出流。(当然,它也可以作为空的输入流)
/dev/zero 该设备无穷尽地提供空字符(ASCII NUL, 0x00),可以使用任何你需要的数目。它通常用于向设备或文件写入字符串0,用于初始化数据存储。(当然,也可作为输出流的接受容器)
两个使用实例如下:
```shell
> dd if=/dev/zero of=~/test.txt bs=1k count=1
产生1KB大小的文件~/text.txt
> find / -name access_log 2>/dev/null
find命令在/目录下查找名为access_log的文件,并且错误输出不会显示出来(文件描述符2被重定向到/dev/null)。
```
## shell编程
### 简单介绍
#### shell脚本与shell
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
而为了方便,通常我们会将shell 脚本编程 叫做shell 编程.注意这两者的区别.
#### shell种类
Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了
- 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)
### shell变量
#### 变量种类
运行shell时,会同时存在三种变量:
- **1) 局部变量** 局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量。
- **2) 环境变量** 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量。
- **3) shell变量** shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
#### 使用变量
```shell
> hello="hello,world"
> echo ${hello} # 建议增加大括号 这样更加哦清晰不容易出错
hello,world
```
注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
#### 传入参数
```shell
> cat inputParameterShell.sh
echo "当前文件名字是 : " $0
echo "第一个参数 : $1"
echo "第二个参数 : $2"
> ./inputParameterShell.sh 122 222
当前文件名字是 : ./inputParameterShell.sh
第一个参数 : 122
第二个参数 : 222
```
#### 特殊变量
```shell
$0:当前脚本的文件名。
$n:n是一个数字,表示第几个参数。
$#:传递给脚本或函数的参数个数。
$*:传递给脚本或函数的所有参数。当被双引号""包含时,会将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。
$@:传递给脚本或函数的所有参数。当被双引号""包含时,仍然将每个参数都看作一份数据,彼此之间是独立的。。
$?:上个命令的退出状态,或函数的返回值。
$$:当前Shell的进程ID。对于Shell脚本,就是这些脚本所在的进程ID。
```
$* 与 $@ 区别:
- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
#### 只读变量
readonly命令
```shell
> echo hello="hello,world"
> echo $hello
hello,world
> hello="afsafafd"
-bash: hello: readonly variable # 这里报错 $hello是只读变量
```
只读变量的取消很麻烦,不知道shell为什么不提供一个接口去取消,不过好在变量只在当前窗口有效,设置成只读了也不要紧
#### 删除变量
unset 命令
```shell
> unset hello # 注意成功不会有任何提升
```
### shell 字符串
#### 单引号
```shell
> a=10
> echo ${a}
10
> tempStr='variable a = ${a}'
> echo ${tempStr}
variable a = ${a} # 注意这里按原样打印
```
单引号字符串的限制:
- 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
- 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。
#### 双引号
```shell
> name='Bob'
> str="Hello, my name is \"${name}\"!"
> echo ${str}
Hello, my name is "Bob"!
```
双引号的优点:
- 双引号里可以有变量
- 双引号里可以出现转义字符
#### 拼接字符串
```shell
> your_name="runoob"
# 使用双引号拼接
> greeting="hello, "$your_name" !"
> greeting_1="hello, ${your_name} !"
> echo $greeting $greeting_1
hello, runoob ! hello, runoob !
# 使用单引号拼接
> greeting_2='hello, '$your_name' !'
> greeting_3='hello, ${your_name} !'
> echo $greeting_2 $greeting_3
hello, runoob ! hello, ${your_name} !
```
#### 获取字符串长度
```
string="abcd"
echo ${#string} #输出 4
```
#### 提取子字符串
以下实例从字符串第 **2** 个字符开始截取 **4** 个字符:
```
string="runoob is a great site"
echo ${string:1:4} # 输出 unoo
```
**注意**:第一个字符的索引值为 **0**。
#### 查找子字符串
查找字符 **i** 或 **o** 的位置(哪个字母先出现就计算哪个):
```
string="runoob is a great site"
echo `expr index "${string}" io` # 输出 4
```
### Shell 数组
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。
#### 定义数组
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
```shell
数组名=(值1 值2 ... 值n)
```
例如:
```shell
array_name=(value0 value1 value2 value3)
```
或者
```shell
array_name=(
value0
value1
value2
value3
)
```
还可以单独定义数组的各个分量:
```shell
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
```
可以不使用连续的下标,而且下标的范围没有限制。
#### 读取数组
读取数组元素值的一般格式是:
```shell
${数组名[下标]}
```
例如:
```shell
valuen=${array_name[n]}
```
使用 **@** 符号可以获取数组中的所有元素,例如:
```shell
echo ${array_name[@]}
```
#### 获取数组的长度
获取数组长度的方法与获取字符串长度的方法相同,例如:
```shell
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
```
### shell基本运算符
Shell 和其他编程语言一样,支持多种运算符,包括:
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用。
expr 是一款表达式计算工具,使用它能完成表达式的求值操作。
例如,两个数相加(**注意使用的是反引号 \**`\** 而不是单引号 \**'\****):
```shell
> val=`expr 2 + 32` # 注意这里要有空格分隔 否则会出错
> echo "两数之和为 : ${val}"
两数之和为 : 34
> val=`expr 2+32`
> echo "两数之和为 : ${val}"
两数之和为 : 2+32
```
#### 算术运算符
下表列出了常用的算术运算符,假定变量 a 为 10,变量 b 为 20:
| 运算符 | 说明 | 举例 |
| :----- | :-------------------------------------------- | :---------------------------- |
| + | 加法 | `expr $a + $b` 结果为 30。 |
| - | 减法 | `expr $a - $b` 结果为 -10。 |
| * | 乘法 比较特殊 需要加 \转义 | `expr $a \* $b` 结果为 200。 |
| / | 除法 | `expr $b / $a` 结果为 2。 |
| % | 取余 | `expr $b % $a` 结果为 0。 |
| = | 赋值 | a=$b 将把变量 b 的值赋给 a。 |
| == | 相等。用于比较两个数字,相同则返回 true。 | [ $a == $b ] 返回 false。 |
| != | 不相等。用于比较两个数字,不相同则返回 true。 | [ $a != $b ] 返回 true。 |
```shell
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a 等于 b"
fi
if [ $a != $b ]
then
echo "a 不等于 b"
fi
```
输出内容
```shell
a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等于 b
```
#### 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:
| 运算符 | 说明 | 举例 |
| :----- | :---------------------------------------------------- | :------------------------- |
| -eq | 检测两个数是否相等,相等返回 true。 | [ $a -eq $b ] 返回 false。 |
| -ne | 检测两个数是否不相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
| -gt | 检测左边的数是否大于右边的,如果是,则返回 true。 | [ $a -gt $b ] 返回 false。 |
| -lt | 检测左边的数是否小于右边的,如果是,则返回 true。 | [ $a -lt $b ] 返回 true。 |
| -ge | 检测左边的数是否大于等于右边的,如果是,则返回 true。 | [ $a -ge $b ] 返回 false。 |
| -le | 检测左边的数是否小于等于右边的,如果是,则返回 true。 | [ $a -le $b ] 返回 true。 |
```shell
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
echo "$a -ne $b: a 不等于 b"
else
echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
echo "$a -gt $b: a 大于 b"
else
echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
echo "$a -lt $b: a 小于 b"
else
echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
echo "$a -ge $b: a 大于或等于 b"
else
echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
echo "$a -le $b: a 小于或等于 b"
else
echo "$a -le $b: a 大于 b"
fi
```
输出内容
```shell
10 -eq 20: a 不等于 b
10 -ne 20: a 不等于 b
10 -gt 20: a 不大于 b
10 -lt 20: a 小于 b
10 -ge 20: a 小于 b
10 -le 20: a 小于或等于 b
```
#### 布尔运算符
下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:
| 运算符 | 说明 | 举例 |
| :----- | :-------------------------------------------------- | :--------------------------------------- |
| ! | 非运算,表达式为 true 则返回 false,否则返回 true。 | [ ! false ] 返回 true。 |
| -o | 或运算,有一个表达式为 true 则返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
| -a | 与运算,两个表达式都为 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
```shell
a=10
b=20
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a == $b: a 等于 b"
fi
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
if [ $a -lt 100 -o $b -gt 100 ]
then
echo "$a 小于 100 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 100 或 $b 大于 100 : 返回 false"
fi
if [ $a -lt 5 -o $b -gt 100 ]
then
echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi
```
输出内容
```shell
10 != 20 : a 不等于 b
10 小于 100 且 20 大于 15 : 返回 true
10 小于 100 或 20 大于 100 : 返回 true
10 小于 5 或 20 大于 100 : 返回 false
```
#### 逻辑运算符
以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:
| 运算符 | 说明 | 举例 |
| :----- | :--------- | :----------------------------------------- |
| && | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
| \|\| | 逻辑的 OR | [[ $a -lt 100 \|\| $b -gt 100 ]] 返回 true |
```shell
a=10
b=20
if [[ $a -lt 100 && $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
if [[ $a -lt 100 || $b -gt 100 ]]
then
echo "返回 true"
else
echo "返回 false"
fi
```
输出内容
```shell
返回 false
返回 true
```
#### 字符串运算符
下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":
| 运算符 | 说明 | 举例 |
| :----- | :------------------------------------------- | :----------------------- |
| = | 检测两个字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
| != | 检测两个字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
| -z | 检测字符串长度是否为0,为0返回 true。 | [ -z $a ] 返回 false。 |
| -n | 检测字符串长度是否不为 0,不为 0 返回 true。 | [ -n "$a" ] 返回 true。 |
| $ | 检测字符串是否为空,不为空返回 true。 | [ $a ] 返回 true。 |
```shell
a="abc"
b="efg"
if [ $a = $b ]
then
echo "$a = $b : a 等于 b"
else
echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
echo "$a != $b : a 不等于 b"
else
echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
echo "-z $a : 字符串长度为 0"
else
echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
echo "-n $a : 字符串长度不为 0"
else
echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
echo "$a : 字符串不为空"
else
echo "$a : 字符串为空"
fi
```
输出内容
```shell
abc = efg: a 不等于 b
abc != efg : a 不等于 b
-z abc : 字符串长度不为 0
-n abc : 字符串长度不为 0
abc : 字符串不为空
```
#### 文件测试运算符
文件测试运算符用于检测 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**: 检测文件是否存在并且是一个符号链接。
变量 file 表示文件 **/var/www/runoob/test.sh**,它的大小为 100 字节,具有 **rwx** 权限。下面的代码,将检测该文件的各种属性:
```shell
file="/var/www/runoob/test.sh"
if [ -r $file ]
then
echo "文件可读"
else
echo "文件不可读"
fi
if [ -w $file ]
then
echo "文件可写"
else
echo "文件不可写"
fi
if [ -x $file ]
then
echo "文件可执行"
else
echo "文件不可执行"
fi
if [ -f $file ]
then
echo "文件为普通文件"
else
echo "文件为特殊文件"
fi
if [ -d $file ]
then
echo "文件是个目录"
else
echo "文件不是个目录"
fi
if [ -s $file ]
then
echo "文件不为空"
else
echo "文件为空"
fi
if [ -e $file ]
then
echo "文件存在"
else
echo "文件不存在"
fi
```
输出结果
```shell
文件可读
文件可写
文件可执行
文件为普通文件
文件不是个目录
文件不为空
文件存在
```
### if判断
Shell 里面的中括号(包括单中括号与双中括号)可用于一些条件的测试:
- 算术比较, 比如一个变量是否为0, `[ $var -eq 0 ]`。
- 文件属性测试,比如一个文件是否存在,`[ -e $var ]`, 是否是目录,`[ -d $var ]`。
- 字符串比较, 比如两个字符串是否相同, `[[ $var1 = $var2 ]]`。
echo 命令
### Shell echo命令
Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于字符串的输出。命令格式:
```
echo string
```
您可以使用echo实现更复杂的输出格式控制。
#### 1.显示普通字符串:
```
echo "It is a test"
```
这里的双引号完全可以省略,以下命令与上面实例效果一致:
```
echo It is a test
```
#### 2.显示转义字符
```
echo "\"It is a test\""
```
结果将是:
```
"It is a test"
```
同样,双引号也可以省略
#### 3.显示变量
read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量
```
read name
echo "$name It is a test"
```
以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:
```
> test.sh
OK #标准输入
OK It is a test #输出
```
#### 4.显示换行
```
echo -e "OK! \n" # -e 开启转义
echo "It is a test"
```
输出结果:
```
OK!
It is a test
```
#### 5.显示不换行
```
#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"
```
输出结果:
```
OK! It is a test
```
#### 6.显示结果定向至文件
```
echo "It is a test" > myfile
```
#### 7.原样输出字符串,不进行转义或取变量(用单引号)
```
echo '$name\"'
```
输出结果:
```
$name\"
```
#### 8.显示命令执行结果
```
echo `date`
```
**注意:** 这里使用的是反引号 **`**, 而不是单引号 **'**。
结果将显示当前日期
```
Thu Jul 24 10:08:46 CST 2014
```
### for循环
```shell
> cat forShell.sh
for file in `ls /`; do #将根目录下的文件打印出来
echo "${file}"
done
> ./forShell.sh
bin
boot
dev
etc
home
init
lib
lib32
lib64
libx32
media
mnt
opt
proc
root
run
sbin
snap
srv
sys
tmp
usr
var
```
## Linux 环境变量
### 读取环境变量
> export
> env
以上这两个命令都可以显示所有的环境变量 好像顺序有些不一样
### 修改环境变量
#### 第一种方式 export修改
> export 变量名=值
小技巧 可以不覆盖之前的值,追加内容
```shell
> export PATH=$PATH:/root/lamp/lamp/
> echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/lamp/lamp/
```
- 生效时间 : 立即生效
- 生效期限: 当前终端中有效,窗口关闭后无效
- 生效范围: 仅对当前用户有效
#### 第二种方式 修改用户目录下的 .bashrc 等文件
`.bashrc `文件可以替换为 `.bash_profile` 或者是 `.profile`
在 ~/.bashrc 文件中最后一行添加
```shell
> export PATH=$PATH:/root/lamp/lamp/
```
- 生效时间 : 新开终端生效,
- 生效期限: 永久有效
- 生效范围: 仅对当前用户有效
- 如果没有上述所说的文件可以创建
#### 第三种方式 修改系统配置文件 例如/etc/bashrc
`/etc/bashrc`文件可以替换为 `/etc/profile` 或者是 `/etc/environment`
需要超级管理员权限
- 生效时间:新开终端生效,或者手动`source /etc/bashrc`生效
- 生效期限:永久有效
- 生效范围:对所有用户有效
### linux加载环境变量原理解析
#### linux加载环境变量的顺序如下
- 系统环境变量 -> 用户自定义环境变量
- /etc/environment -> /etc/profile -> ~/.profile -> ~/.bashrc
#### 几个需要注意的点
- 打开 /etc/profile 文件你会发现 该文件会加载 /etc/bash.bashrc 文件,然后检查/etc/profile.d 目录下的.sh 文件并加载
- 从`~/.profile`文件中代码不难发现,`/.profile`文件**只在用户登录的时候读取一次**,而`/.bashrc`会在每次运行`Shell`脚本的时候读取一次。
#### 小技巧
可以自定义一个环境变量文件,比如在某个项目下定义`uusama.profile`,在这个文件中使用`export`定义一系列变量,然后在`~/.profile`文件后面加上:`sourc uusama.profile`,这样你每次登陆都可以在Shell脚本中使用自己定义的一系列变量。
也可以使用`alias`命令定义一些命令的别名,比如`alias rm="rm -i"`(双引号必须),并把这个代码加入到`~/.profile`中,这样你每次使用`rm`命令的时候,都相当于使用`rm -i`命令,非常方便。
#### 各种文件
##### /etc/environment 文件
```shell
> cat /etc/environment
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
> echo $PATH # path路径就是上边设置的
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
```
##### /etc/profile 文件
加载了/etc/bash.bashrc文件,并检查/etc/profile.d 目录下的.sh 文件并加载
```shell
> cat /etc/profile
# /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
# and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
if [ "${PS1-}" ]; then
if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
# The file bash.bashrc already sets the default PS1.
# PS1='\h:\w\$ '
if [ -f /etc/bash.bashrc ]; then # 如果/etc/bash.bashrc是普通文件
. /etc/bash.bashrc # 加载/etc/bash.bashrc 文件
fi
else
if [ "`id -u`" -eq 0 ]; then #判断用户是不是root 如果是root 改变符号为# 否则是$
PS1='# '
else
PS1='$ '
fi
fi
fi
#检查/etc/profile.d 目录下的.sh 文件并加载
if [ -d /etc/profile.d ]; then # 检查/etc/profile.d是否为目录
for i in /etc/profile.d/*.sh; do
if [ -r $i ]; then # 判断文件是否可读
. $i
fi
done
unset i
fi
```
##### bash.bashrc文件
```shell
> cat /etc/bash.bashrc
# System-wide .bashrc file for interactive bash(1) shells.
# To enable the settings / commands in this file for login shells as well,
# this file has to be sourced in /etc/profile.
# If not running interactively, don't do anything
[ -z "$PS1" ] && return # 检测字符串长度是否为0,为0返回 true。
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize # -s:激活指定的shell行为选项;
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, overwrite the one in /etc/profile)
# but only if not SUDOing and have SUDO_PS1 set; then assume smart user.
if ! [ -n "${SUDO_USER}" -a -n "${SUDO_PS1}" ]; then
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
# Commented out, don't overwrite xterm -T "title" -n "icontitle" by default.
# If this is an xterm set the title to user@host:dir
#case "$TERM" in
#xterm*|rxvt*)
# PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
# ;;
#*)
# ;;
#esac
# enable bash completion in interactive shells
#if ! shopt -oq posix; then
# if [ -f /usr/share/bash-completion/bash_completion ]; then
# . /usr/share/bash-completion/bash_completion
# elif [ -f /etc/bash_completion ]; then
# . /etc/bash_completion
# fi
#fi
# sudo hint 提示用户使用 sudo
if [ ! -e "$HOME/.sudo_as_admin_successful" ] && [ ! -e "$HOME/.hushlogin" ] ; then
case " $(groups) " in *\ admin\ *|*\ sudo\ *)
if [ -x /usr/bin/sudo ]; then
cat <<-EOF
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
EOF
fi
esac
fi
# /usr/lib/command-not-found 竟然是个python脚本
# if the command-not-found package is installed, use it
if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then
function command_not_found_handle {
# check because c-n-f could've been removed in the meantime
if [ -x /usr/lib/command-not-found ]; then
/usr/lib/command-not-found -- "$1"
return $?
elif [ -x /usr/share/command-not-found/command-not-found ]; then
/usr/share/command-not-found/command-not-found -- "$1"
return $?
else
printf "%s: command not found\n" "$1" >&2
return 127
fi
}
fi
```
##### /etc/profile.d/ 目录
```shell
> ll
total 36
drwxr-xr-x 1 root root 4096 Aug 5 06:07 ./
drwxr-xr-x 1 root root 4096 Oct 1 10:10 ../
-rw-r--r-- 1 root root 96 Dec 5 2019 01-locale-fix.sh
-rw-r--r-- 1 root root 1557 Feb 17 2020 Z97-byobu.sh
-rwxr-xr-x 1 root root 3417 Jun 3 00:12 Z99-cloud-locale-test.sh*
-rwxr-xr-x 1 root root 873 Jun 3 00:12 Z99-cloudinit-warnings.sh*
-rw-r--r-- 1 root root 825 Jul 10 21:59 apps-bin-path.sh
-rw-r--r-- 1 root root 729 Feb 2 2020 bash_completion.sh
-rw-r--r-- 1 root root 1003 Aug 13 2019 cedilla-portuguese.sh
-rw-r--r-- 1 root root 1107 Nov 4 2019 gawk.csh
-rw-r--r-- 1 root root 757 Nov 4 2019 gawk.sh
-rwxr-xr-x 1 root root 903 Dec 13 2019 update-motd.sh*
```
##### .profile 文件
.profile 文件加载了 .bashrc 文件
```shell
> cat .profile
# ~/.profile: executed by Bourne-compatible login shells.
if [ "$BASH" ]; then
if [ -f ~/.bashrc ]; then
. ~/.bashrc # 加载.bashrc 文件
fi
fi
mesg n 2> /dev/null || true
```
##### .bashrc文件
```shell
> cat /root/.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
# don't put duplicate lines in the history. See bash(1) for more options
# ... or force ignoredups and ignorespace
HISTCONTROL=ignoredups:ignorespace
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# make less more friendly for non-text input files, see lesspipe(1)
[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)" # eval 二次执行内容
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "$debian_chroot" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
alias grep='grep --color=auto'
alias fgrep='fgrep --color=auto'
alias egrep='egrep --color=auto'
fi
# some more ls aliases
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
#if [ -f /etc/bash_completion ] && ! shopt -oq posix; then
# . /etc/bash_completion
#fi
```
## linux的两个关键文件
### /etc/passwd 文件
/etc/passwd文件中每个用户都有一个对应的记录行,它记录了这个用户的一些基本属性。系统管理员经常会接触到这个文件的修改以完成对用户的管理工作。
用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shellz
```shell
> cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:112::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:113::/nonexistent:/usr/sbin/nologin
sshd:x:109:65534::/run/sshd:/usr/sbin/nologin
landscape:x:110:115::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:111:1::/var/cache/pollinate:/bin/false
yhn:x:1000:1000:,,,:/home/yhn:/bin/bash
```
一些系统中,存放着加密后的用户口令字。虽然这个字段存放的只是用户口令的加密串,不是明文,但是由于/etc/passwd文件对所有用户都可读,所以这仍是一个安全隐患。因此,现在许多Linux系统(如SVR4)都使用了shadow技术,把真正的加密后的用户口令字存放到/etc/shadow文件中,而在/etc/passwd文件的口令字段中只存放一个特殊的字符,例如“x”或者“*”。
### /etc/shadow文件
1、账户名称
2、加密后的密码,如果这一栏的第一个字符为!或者*的话,说明这是一个不能登录的账户,从上面可以看出,ubuntu默认的就不启用root账户。
3、最近改动密码的日期(这个是从1970年1月1日算起的总的天数)。
4、密码不可被变更的天数:设置了这个值,则表示从变更密码的日期算起,多少天内无法再次修改密码,如果是0的话,则没有限制
5、密码需要重新变更的天数:如果为99999则没有限制
6、密码过期预警天数
7、密码过期的宽恕时间:如果在5中设置的日期过后,用户仍然没有修改密码,则该用户还可以继续使用的天数
8、账号失效日期,过了这个日期账号就无法使用
```shell
> cat /etc/shadow
root:*:18478:0:99999:7:::
daemon:*:18478:0:99999:7:::
bin:*:18478:0:99999:7:::
sys:*:18478:0:99999:7:::
sync:*:18478:0:99999:7:::
games:*:18478:0:99999:7:::
man:*:18478:0:99999:7:::
lp:*:18478:0:99999:7:::
mail:*:18478:0:99999:7:::
news:*:18478:0:99999:7:::
uucp:*:18478:0:99999:7:::
proxy:*:18478:0:99999:7:::
www-data:*:18478:0:99999:7:::
backup:*:18478:0:99999:7:::
list:*:18478:0:99999:7:::
irc:*:18478:0:99999:7:::
gnats:*:18478:0:99999:7:::
nobody:*:18478:0:99999:7:::
systemd-network:*:18478:0:99999:7:::
systemd-resolve:*:18478:0:99999:7:::
systemd-timesync:*:18478:0:99999:7:::
messagebus:*:18478:0:99999:7:::
syslog:*:18478:0:99999:7:::
_apt:*:18478:0:99999:7:::
tss:*:18478:0:99999:7:::
uuidd:*:18478:0:99999:7:::
tcpdump:*:18478:0:99999:7:::
sshd:*:18478:0:99999:7:::
landscape:*:18478:0:99999:7:::
pollinate:*:18478:0:99999:7:::
yhn:$6$H1kSprOVLc0wIUJj$Vkw8FiemI9tTy9nSj4TPo4Jobf/J.euYwn1O89hKHU7auK9aO1UcnmMM1Qgpuw5K0:18535:0:99999:7:::
```
## 重要命令
### find
#### 列出给定目录(base_path)下所有的文件和子目录:
> find 路径
```shell
> find . # 查看当前目录及其子目录文件
```
#### 基于目录深度的搜索
```shell
find . -maxdepth 1 # 只扫描本文件夹中的内容
```
find命令指定遍历完所有的子目录。使用-maxdepth和-mindepth可以限制find命令遍历的目录深度,并且find命令默认不搜索符号链接,可以用-L选项改变这种行为。
#### 基于文件类型搜索
使用-type可以指定搜索的文件类型,linux/unix将所有的的一切都视为文件(文件类型有:普通文件f,目录d,符号链接 l,字符设备c,块设备b,套接字s,FIFO-p),使用 -type选项我们能够对文件类型进行过滤。
```shell
find . -type d # 只会找文件夹
```
#### 根据文件的时间戳进行搜索
Linux/Unix文件系统中的每一个文件都有三种时间戳,访问时间(-atime),修改时间(-mtime),变化时间(-ctime),单位为天数,用整数指定,数字前加上+,表示大于这个时间;加上-,表示小于这个天数;不加表示刚好这个天数。
```shell
find . -atime -1 # 查找访问时间小于1天的
```
当然相应的用分钟作为单位就可以用选项(-amin)(-mmin)(-cmin),
#### 基于文件大小的搜索
find提供了指定文件大小的单位选项进而搜索符合大小文件的功能,这个搜索也常常会让用户感到非常舒服(b:块, c:字节, w:字, k:千字节, M:兆字节, G:吉字节)。
在搜索之前我们先用ls(list)指令来查看下当前目录下的文件信息:
```shell
> ll
total 28
drwxr-xr-x 1 yhn yhn 4096 Oct 1 21:01 ./
drwxr-xr-x 1 root root 4096 Sep 30 19:48 ../
-rw------- 1 yhn yhn 3426 Oct 1 21:06 .bash_history
-rw-r--r-- 1 yhn yhn 220 Sep 30 19:48 .bash_logout
-rw-r--r-- 1 yhn yhn 3771 Sep 30 19:48 .bashrc
drwxr-xr-x 1 yhn yhn 4096 Sep 30 19:48 .landscape/
-rw-r--r-- 1 yhn yhn 0 Oct 1 09:03 .motd_shown
-rw-r--r-- 1 yhn yhn 807 Sep 30 19:48 .profile
-rw------- 1 yhn yhn 7 Oct 1 20:36 .python_history
drwx------ 1 yhn yhn 4096 Oct 1 13:10 .ssh/
-rw-r--r-- 1 yhn yhn 0 Sep 30 19:49 .sudo_as_admin_successful
-rw------- 1 yhn yhn 7296 Oct 1 21:01 .viminfo
-rw-r--r-- 1 root root 20 Oct 1 20:01 abc
-rwxr-xr-x 1 root root 40 Oct 1 20:01 abc.sh*
-rw-rw-r-- 1 yhn yhn 13 Oct 1 21:01 bbb.sh
drwxr-xr-x 1 yhn yhn 4096 Oct 1 15:03 shellScriptLearn/
```
```shell
> find . -maxdepth 1 -size +4000c # 查找字节大于4000的文件或者目录
.
./.landscape
./.ssh
./.viminfo
./shellScriptLearn
```
#### **基于文件权限和所有权的匹配**
perm选项指定了find指匹配指定权限的文件,参数为文件对应的权限码。
```shell
find . -perm 664 # 查找权限是664的文件或者目录 rw-rw-r--
```
#### **指定find跳过特定的目录**
使用-prune选项可以跳过我们在搜寻的的一些明显我们不需要的目录
```shell
find . -path ./shellScriptLearn -prune -o -print # 设置跳过当前目录的shellScriptLearn 文件夹
```
#### **否定参数,可以用 !排除所指定到的模式**
```shell
find . -maxdepth 1 ! -name '*.sh' # 不寻找所有以.sh结尾的文件
```
### mount
#### wsl挂载u盘
WSL比起linux挂载硬盘简单一些。而且windows本身自己的硬盘位ntfs格式,所以移动硬盘感觉挂载要比单纯的linu下ntfs挂载更加稳定一些
假设你的移动硬盘在windows下显示为 E:\
##### 一 .新建文件夹e
```shell
sudo mkdir /mnt/e
```
##### 二.挂载盘符e
```shell
sudo mount -t drvfs e: /mnt/e
```
##### 三.大功告成。
进入/mnt/e即可与windows下一摸一样。
##### 四.弹出移动硬盘,
这样才能在windows下正常弹出,否则是会一直占用的。
```shell
sudo umount /mnt/e
```
下一次重新重新挂载直接进行步骤2即可。
### mkdir
创建文件树
```shell
> mkdir -vp helloword/{lib,src,bin/{music,docs},res}
mkdir: created directory 'helloword'
mkdir: created directory 'helloword/lib'
mkdir: created directory 'helloword/src'
mkdir: created directory 'helloword/bin'
mkdir: created directory 'helloword/bin/music'
mkdir: created directory 'helloword/bin/docs'
mkdir: created directory 'helloword/res'
> tree helloword/
helloword/
├── bin
│ ├── docs
│ └── music
├── lib
├── res
└── src
```
### ln
#### 简介
在 Windows 系统中,快捷方式是指向原始文件的一个链接文件。可以让用户从不同的位置来访问原始的文件;原文件一旦被删除或剪切到其他地方后,会导致链接文件失效。
但是在 Linux 系统中,"快捷方式"就不太一样 。在 Linux 系统存在硬链接和软链接两种文件。
| 参数 | 作用 |
| ---- | -------------------------------------------- |
| -s | 创建软链接(如果不带 -s 参数,默认创建硬链接) |
| -f | 强制创建文件或目录的链接 |
| -i | 覆盖前先询问 |
| -v | 显示创建链接的过程 |
#### 硬链接
硬链接(hard link) : 可以将它理解为一个 “指向原始文件 inode 的指针”,系统不为它分配独立的 inode 和 文件。所以,硬链接文件与原始文件其实是同一个文件,只是名字不同。我们每添加一个硬链接,该文件的 innode 连接数就会增加 1 ; 而且只有当该文件的 inode 连接数为 0 时,才算彻底被将它删除。因此即便删除原始文件,依然可以通过硬链接文件来访问。需要注意的是,我们不能跨分区对文件进行链接。
##### 硬链接创建
![img](http://img.hi-cat.cn/d9695fe12467b241ccd6b37d75caa693)
此时新建一个硬链接
```
ln fileName newFileName
```
![img](http://img.hi-cat.cn/c90492e9ead20dd1a7764e90d946550b)
##### 删除文件
删除原文件
![img](http://img.hi-cat.cn/54ceb38017aa43253724fb275448123c)
或者删除硬链接文件 :
![img](https://img.hi-cat.cn/c69af7d0288a2d92d1c179fcfc1e08cd)
#### 软连接
软链接(symbolic link) : 等同于 Windows 系统下的快捷方式。仅仅包括所含链接文件的路径名字。因此能链接目录,也能跨文件系统链接。但是,当删除原始文件后,链接文件也将失效。
### tar
```shell
> tar cvf abc.tar.xz *
> tar xvf abc.tar.xz *
```
### who
### locate
locate(locate) 命令用来查找文件或目录。 locate命令要比find -name快得多,原因在于它不搜索具体目录,而是搜索一个数据库/var/lib/mlocate/mlocate.db 。这个数据库中含有本地所有文件信息。Linux系统自动创建这个数据库,并且每天自动更新一次,因此,我们在用whereis和locate 查找文件时,有时会找到已经被删除的数据,或者刚刚建立文件,却无法查找到,原因就是因为数据库文件没有被更新。为了避免这种情况,可以在使用locate之前,先使用updatedb命令,手动更新数据库。整个locate工作其实是由四部分组成的:
/usr/bin/updatedb 主要用来更新数据库,通过crontab自动完成的
/usr/bin/locate 查询文件位置
/etc/updatedb.conf updatedb的配置文件
/var/lib/mlocate/mlocate.db 存放文件数据库的文件
```shell
-b, --basename match only the base name of path names
-c, --count 只输出找到的数量
-d, --database DBPATH 使用DBPATH指定的数据库,而不是默认数据库 /var/lib/mlocate/mlocate.db
-e, --existing only print entries for currently existing files
-L, --follow follow trailing symbolic links when checking file existence (default)
-h, --help 显示帮助
-i, --ignore-case 忽略大小写
-l, --limit, -n LIMIT limit output (or counting) to LIMIT entries
-m, --mmap ignored, for backward compatibility
-P, --nofollow, -H don't follow trailing symbolic links when checking file existence
-0, --null separate entries with NUL on output
-S, --statistics don't search for entries, print statistics about eachused database
-q, --quiet 安静模式,不会显示任何错误讯息
-r, --regexp REGEXP 使用基本正则表达式
--regex 使用扩展正则表达式
-s, --stdio ignored, for backward compatibility
-V, --version 显示版本信息
-w, --wholename match whole path name (default)
```
```shell
[root@cent6 ~]# cat /etc/updatedb.conf
PRUNE_BIND_MOUNTS = "yes"
PRUNEFS = "9p afs anon_inodefs auto autofs bdev binfmt_misc cgroup cifs coda configfs cpuset debugfs devpts ecryptfs exofs fuse fusectl gfs gfs2 hugetlbfs inotifyfs iso9660 jffs2 lustre mqueue ncpfs nfs nfs4 nfsd pipefs proc ramfs rootfs rpc_pipefs securityfs selinuxfs sfs sockfs sysfs tmpfs ubifs udf usbfs"
PRUNENAMES = ".git .hg .svn"
PRUNEPATHS = "/afs /media /net /sfs /tmp /udev /var/cache/ccache /var/spool/cups /var/spool/squid /var/tmp"
```
第一行PRUNE_BIND_MOUNTS="yes"的意思是:是否进行限制搜索。
第二行是排除检索的文件系统类型,即列出的文件系统类型不进行检索。
第二行表示对哪些后缀的文件排除检索,也就是列在这里面的后缀的文件跳过不进行检索。不同后缀之间用空格隔开。
第四行是排除检索的路径,即列出的路径下的文件和子文件夹均跳过不进行检索。updatedb之后使用locate仍然找不到想要文件
可以检查挂载的目录是否被忽略了
### crontab
#### cron介绍
我们经常使用的是crontab命令是cron table的简写,它是cron的配置文件,也可以叫它作业列表,我们可以在以下文件夹内找到相关配置文件。
- /var/spool/cron/ 目录下存放的是每个用户包括root的crontab任务,每个任务以创建者的名字命名
- /etc/crontab 这个文件负责调度各种管理和维护任务。
- /etc/cron.d/ 这个目录用来存放任何要执行的crontab文件或脚本。
- 我们还可以把脚本放在/etc/cron.hourly、/etc/cron.daily、/etc/cron.weekly、/etc/cron.monthly目录中,让它每小时/天/星期、月执行一次。
#### crontab的使用
我们常用的命令如下:
```
crontab [-u username] //省略用户表表示操作当前用户的crontab
-e (编辑工作表)
-l (列出工作表里的命令)
-r (删除工作作)
```
我们用**crontab -e**进入当前用户的工作表编辑,是常见的vim界面。每行是一条命令。
crontab的命令构成为 时间+动作,其时间有**分、时、日、月、周**五种,操作符有
- ***** 取值范围内的所有数字
- **/** 每过多少个数字
- **-** 从X到Z
- **,**散列数字
------
#### 实例
#### 实例1:每1分钟执行一次myCommand
```
* * * * * myCommand
```
#### 实例2:每小时的第3和第15分钟执行
```
3,15 * * * * myCommand
```
#### 实例3:在上午8点到11点的第3和第15分钟执行
```
3,15 8-11 * * * myCommand
```
#### 实例4:每隔两天的上午8点到11点的第3和第15分钟执行
```
3,15 8-11 */2 * * myCommand
```
#### 实例5:每周一上午8点到11点的第3和第15分钟执行
```
3,15 8-11 * * 1 myCommand
```
#### 实例6:每晚的21:30重启smb
```
30 21 * * * /etc/init.d/smb restart
```
#### 实例7:每月1、10、22日的4 : 45重启smb
```
45 4 1,10,22 * * /etc/init.d/smb restart
```
#### 实例8:每周六、周日的1 : 10重启smb
```
10 1 * * 6,0 /etc/init.d/smb restart
```
#### 实例9:每天18 : 00至23 : 00之间每隔30分钟重启smb
```
0,30 18-23 * * * /etc/init.d/smb restart
```
#### 实例10:每星期六的晚上11 : 00 pm重启smb
```
0 23 * * 6 /etc/init.d/smb restart
```
#### 实例11:每一小时重启smb
```
* */1 * * * /etc/init.d/smb restart
```
#### 实例12:晚上11点到早上7点之间,每隔一小时重启smb
```
* 23-7/1 * * * /etc/init.d/smb restart
```
### anacron
anacron 是用来做什么的呢?设想这样一个场景,Linux 服务器会在周末关机两天,但是设定的定时任务大多在周日早上进行,但在这个时间点,服务器又处于关机状态,导致系统很多定时任务无法运行。
又比如,我们需要在凌晨 5 点 05 分执行系统的日志备份,但 Linux 服务器不是 24 小时开机的,在晚上需要关机,白天上班之后才会再次开机,在这个定时任务的执行时间我们的服务器刚好没有开机,那么这个定时任务就不会执行了。anacron 就是用来解决这个问题的。
anacron 会以 1 天、1周(7天)、一个月作为检测周期,判断是否有定时任务在关机之后没有执行。如果有这样的任务,那么 anacron 会在特定的时间重新执行这些定时任务。
那么,anacron 是如何判断这些定时任务已经超过执行时间的呢?这就需要借助 anacron 读取的时间记录文件。anacron 会分析现在的时间与时间记录文件所记载的上次执行 anacron 的时间,将两者进行比较,如果两个时间的差值超过 anacron 的指定时间差值(一般是 1 天、7 天和一个月),就说明有定时任务没有执行,这时 anacron 会介入并执行这个漏掉的定时任务,从而保证在关机时没有执行的定时任务不会被漏掉。
在当前的 Linux 中,其实不需要执行任何 anacron 命令,只需要配置好 /etc/anacrontab 文件,系统就会依赖这个文件中的设定来通过 anacron 执行定时任务了。那么,关键就是 /etc/anacrontab 文件的内容了。这个文件的内容如下:
```shell
vi /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root
#前面的内容和/etc/crontab类似
#the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45
#最大随机廷迟
#the jobs will be started during the following hours only
START_H0URS_RANGE=3-22
#fanacron的执行时间范围是3:00~22:00
#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily
#每天开机 5 分钟后就检查 /etc/cron.daily 目录内的文件是否被执行,如果今天没有被执行,那就执行
7 25 cron.weekly nice run-parts /etc/cron.weekly
#每隔 7 天开机后 25 分钟检查 /etc/cron.weekly 目录内的文件是否被执行,如果一周内没有被执行,就会执行
©monthly 45 cron.monthly nice run-parts /etc/cron.monthly
#每隔一个月开机后 45 分钟检查 /etc/cron.monthly 目录内的文件是否被执行,如果一个月内没有被执行,那就执行
```
我们用 cron.daily 工作来说明一下 /etc/anacrontab 的执行过程:
1. 读取 /var/spool/anacron/cron.daily 文件中 anacron 上一次执行的时间。
2. 和当前时间比较,如果两个时间的差值超过 1 天,就执行 cron.daily 工作。
3. 只能在 03:00-22:00 执行这个工作。
4. 执行工作时强制延迟时间为 5 分钟,再随机延迟 0~45 分钟。
5. 使用 nice 命令指定默认优先级,使用 run-parts 脚本执行 /etc/cron.daily 目录中所有的可执行文件。
### ll
**drwxr-xr-x 2 root root 48 2013-11-27 16:34 test/**
第一个栏位,表示文件的属性。Linux的文件基本上分为三个属性:可读(r),可写(w),可执行(x)。
```
这里有十个格子可以添(具体程序实现时,实际上是十个bit位)。
```
第一个字母表示文件类型,
”-”,普通文件.
”d”目录,字母”d”,是dirtectory(目录)的缩写.
“l”符号链接。请注意,一个目录或者说一个文件夹是一个特殊文件,这个特殊文件存放的是其他文件和文件夹的相关信息.
“b”块设备文件。
“c”字符设备文件。
```
紧接着的3*3个字符分3组,各指示此文件的读、写、执行权限,对于owner、group、others而言。
因为Linux是多用户多任务系统,所以一个文件可能同时被许多人使用,所以我们一定要设好每个文件的权限,其文件的权限位置排列顺序是(以-rwxr-xr-x为例):
rwx(Owner)r-x(Group)r-x(Other)
这个例子表示的权限是:使用者自己可读,可写,可执行;同一组的用户可读,不可写,可执行;其它用户可读,不可写,可执行。
另外,有一些程序属性的执行部分不是X,而是S,这表示执行这个程序的使用者,临时可以有和拥有者一样权力的身份来执行该程序。一般出现在系统管理之类的指令或程序,让使用者执行时,拥有root身份。
```
第二个栏位,表示文件个数。如果是文件的话,那这个数目自然是1了,如果是目录的话,那它的数目就是该目录中的文件个数了。
第三个栏位,表示该文件或目录的拥有者。若使用者目前处于自己的Home,那这一栏大概都是它的账号名称。
第四个栏位,表示所属的组(group)。每一个使用者都可以拥有一个以上的组,不过大部分的使用者应该都只属于一个组,只有当[系统管理员](http://zhidao.baidu.com/search?word=系统管理员&fr=qb_search_exp&ie=utf8)希望给予某使用者特殊权限时,才可能会给他另一个组。
第五栏位,表示文件大小。文件大小用byte来表示,而空目录一般都是1024byte,当然可以用其它参数使文件显示的单位不同,如使用ls –k就是用kb莱显示一个文件的大小单位,不过一般我们还是以byte为主。
第六个栏位,表示最后一次修改时间。以“月,日,时间”的格式表示,如Aug 15 5:46表示8月15日早上5:46分。
第七个栏位,表示文件名。我们可以用ls –a显示隐藏的文件名。
### umask
```shell
> umask -S
u=rwx,g=rwx,o=rx
```
### 用户管理
#### useradd(添加)
```
useradd 选项 用户名
```
参数说明:
- 选项:
- -c comment 指定一段注释性描述。
- -d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。
- -g 用户组 指定用户所属的用户组。
- -G 用户组,用户组 指定用户所属的附加组。
- -s Shell文件 指定用户的登录Shell。
- -u 用户号 指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。
- 用户名:
指定新账号的登录名。
##### 实例1
```
# useradd –d /home/sam -m sam
```
此命令创建了一个用户sam,其中-d和-m选项用来为登录名sam产生一个主目录 /home/sam(/home为默认的用户主目录所在的父目录)。
#### userdel(删除帐号)
如果一个用户的账号不再使用,可以从系统中删除。删除用户账号就是要将/etc/passwd等系统文件中的该用户记录删除,必要时还删除用户的主目录。
删除一个已有的用户账号使用userdel命令,其格式如下:
userdel 选项 用户名
常用的选项是 -r,它的作用是把用户的主目录一起删除。
例如:
```shell
> userdel -r sam
```
此命令删除用户sam在系统文件中(主要是/etc/passwd, /etc/shadow, /etc/group等)的记录,同时删除用户的主目录。
#### usermod(修改帐号)
修改用户账号就是根据实际情况更改用户的有关属性,如用户号、主目录、用户组、登录Shell等。
修改已有用户的信息使用`usermod`命令,其格式如下:
```shell
usermod 选项 用户名
```
常用的选项包括`-c, -d, -m, -g, -G, -s, -u以及-o等`,这些选项的意义与`useradd`命令中的选项一样,可以为用户指定新的资源值。
另外,有些系统可以使用选项:-l 新用户名
这个选项指定一个新的账号,即将原来的用户名改为新的用户名。
例如:
```shell
> usermod -s /bin/ksh -d /home/z –g developer sam
```
此命令将用户sam的登录Shell修改为ksh,主目录改为/home/z,用户组改为developer。
#### 用户口令的管理
用户管理的一项重要内容是用户口令的管理。用户账号刚创建时没有口令,但是被系统锁定,无法使用,必须为其指定口令后才可以使用,即使是指定空口令。
指定和修改用户口令的Shell命令是passwd。超级用户可以为自己和其他用户指定口令,普通用户只能用它修改自己的口令。命令的格式为:
```shell
passwd 选项 用户名
```
可使用的选项:
- -l 锁定口令,即禁用账号。
- -u 口令解锁。
- -d 使账号无口令。
- -f 强迫用户下次登录时修改口令。
如果默认用户名,则修改当前用户的口令。
例如,假设当前用户是sam,则下面的命令修改该用户自己的口令:
```shell
$ passwd
Old password:******
New password:*******
Re-enter new password:*******
```
如果是超级用户,可以用下列形式指定任何用户的口令:
```
passwd sam
New password:*******
Re-enter new password:*******
```
普通用户修改自己的口令时,passwd命令会先询问原口令,验证后再要求用户输入两遍新口令,如果两次输入的口令一致,则将这个口令指定给用户;而超级用户为用户指定口令时,就不需要知道原口令。
为了系统安全起见,用户应该选择比较复杂的口令,例如最好使用8位长的口令,口令中包含有大写、小写字母和数字,并且应该与姓名、生日等不相同。
为用户指定空口令时,执行下列形式的命令:
```shell
passwd -d sam
```
passwd 命令还可以用 -l(lock) 选项锁定某一用户,使其不能登录,例如:
```shell
passwd -l sam
```
### 磁盘管理
#### fdisk
```shell
> fdisk -l
... 省略
Disk /dev/sdc:28.67 GiB,30765219840 字节,60088320 个扇区
Disk model: Cruzer Glide 3.0
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x2cba192c
设备 启动 起点 末尾 扇区 大小 Id 类型
/dev/sdc1 * 2048 60088319 60086272 28.7G 7 HPFS/NTFS/exFA
... 省略
```
#### mount
```shell
# mount /dev/sdc1 /mnt/随便一个文件夹
> mount /dev/sdc1 /mnt/aaa
```
#### umount
```shell
# umount /mnt/你之前挂载的文件夹
> umount /mnt/aaa
```
### sort命令
```shell
> sort -t: -k1,1 /etc/passwd #意思是 用冒号: 分割 第一列按照字母表顺序排序
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
avahi:x:115:121:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
avahi-autoipd:x:109:116:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
colord:x:121:126:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
cups-pk-helper:x:113:120:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
games:x:5:60:games:/usr/games:/usr/sbin/nologin
gdm:x:125:130:Gnome Display Manager:/var/lib/gdm3:/bin/false
geoclue:x:122:127::/var/lib/geoclue:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
gnome-initial-setup:x:124:65534::/run/gnome-initial-setup/:/bin/false
hplip:x:119:7:HPLIP system user,,,:/run/hplip:/bin/false
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
kernoops:x:116:65534:Kernel Oops Tracking Daemon,,,:/:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
nm-openvpn:x:118:124:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
pulse:x:123:128:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
root:x:0:0:root:/root:/bin/bash
rtkit:x:111:117:RealtimeKit,,,:/proc:/usr/sbin/nologin
saned:x:117:123::/var/lib/saned:/usr/sbin/nologin
speech-dispatcher:x:114:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false
sync:x:4:65534:sync:/bin:/bin/sync
sys:x:3:3:sys:/dev:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
tcpdump:x:108:115::/nonexistent:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
usbmux:x:110:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
uuidd:x:107:114::/run/uuidd:/usr/sbin/nologin
whoopsie:x:120:125::/nonexistent:/bin/false
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
yhn:x:1000:1000:yhn,,,:/home/yhn:/bin/bash
> sort -t: -k4n -k3n /etc/passwd #以冒号隔开,先以第四段进行排序,然后以第三段进行排序,展示出来(从1开始计数)
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
hplip:x:119:7:HPLIP system user,,,:/run/hplip:/bin/false
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
speech-dispatcher:x:114:29:Speech Dispatcher,,,:/run/speech-dispatcher:/bin/false
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
usbmux:x:110:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
games:x:5:60:games:/usr/games:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
systemd-timesync:x:102:104:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:106::/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
tss:x:106:111:TPM software stack,,,:/var/lib/tpm:/bin/false
uuidd:x:107:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:108:115::/nonexistent:/usr/sbin/nologin
avahi-autoipd:x:109:116:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
rtkit:x:111:117:RealtimeKit,,,:/proc:/usr/sbin/nologin
cups-pk-helper:x:113:120:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin
avahi:x:115:121:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
saned:x:117:123::/var/lib/saned:/usr/sbin/nologin
nm-openvpn:x:118:124:NetworkManager OpenVPN,,,:/var/lib/openvpn/chroot:/usr/sbin/nologin
whoopsie:x:120:125::/nonexistent:/bin/false
colord:x:121:126:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
geoclue:x:122:127::/var/lib/geoclue:/usr/sbin/nologin
pulse:x:123:128:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
gdm:x:125:130:Gnome Display Manager:/var/lib/gdm3:/bin/false
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
yhn:x:1000:1000:yhn,,,:/home/yhn:/bin/bash
sync:x:4:65534:sync:/bin:/bin/sync
_apt:x:105:65534::/nonexistent:/usr/sbin/nologin
dnsmasq:x:112:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
kernoops:x:116:65534:Kernel Oops Tracking Daemon,,,:/:/usr/sbin/nologin
gnome-initial-setup:x:124:65534::/run/gnome-initial-setup/:/bin/false
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
```
### tree
```
-a 显示所有文件和目录。
-A 使用ASNI绘图字符显示树状图而非以ASCII字符组合。
-C 在文件和目录清单加上色彩,便于区分各种类型。
-d 显示目录名称而非内容。
-D 列出文件或目录的更改时间。
-f 在每个文件或目录之前,显示完整的相对路径名称。
-F 在执行文件,目录,Socket,符号连接,管道名称名称,各自加上"*","/","=","@","|"号。
-g 列出文件或目录的所属群组名称,没有对应的名称时,则显示群组识别码。
-i 不以阶梯状列出文件或目录名称。
-L level 限制目录显示层级。
-l 如遇到性质为符号连接的目录,直接列出该连接所指向的原始目录。
-n 不在文件和目录清单加上色彩。
-N 直接列出文件和目录名称,包括控制字符。
-p 列出权限标示。
-P<范本样式> 只显示符合范本样式的文件或目录名称。
-q 用"?"号取代控制字符,列出文件和目录名称。
-s 列出文件或目录大小。
-t 用文件和目录的更改时间排序。
-u 列出文件或目录的拥有者名称,没有对应的名称时,则显示用户识别码。
-x 将范围局限在现行的文件系统中,若指定目录下的某些子目录,其存放于另一个文件系统上,则将该子目录予以排除在寻找范围外。
```
```shell
> pwd
/sys
# -L level 限制目录显示层级。
> tree . -L 1 # 限制展示层级为1 和ls功能 一致
.
├── block
├── bus
├── class
├── dev
├── devices
├── firmware
├── fs
├── hypervisor
├── kernel
├── module
└── power
11 directories, 0 files
```
## 编译
### 防止C语言头文件被重复包含
#### 第一种方法
当1个C语言程序由 多个 源程序文件 组成时,由于每个 源程序文件 都有 #include <…> #include “…h”, 最终它们可能形成交叉包含和重复包含现象,从而造成错误。
为了避免这种情况发生,可以 采用 定义宏 的方法 把各内个头文件 包起来。
编译器 在正式编译的开始,现处理宏---- 也就是“预编译命令".
用 宏(#号开始的行) 把 头文件内容容 包起来:
```c
#ifndef HEADER_One_H // 意思是:宏开始行,如果还没有定义 HEADER_One_H 则进入,否则退出
#define HEADER_One_H //定义 HEADER_One_H
header1.h头文件内容
#endif // 宏结束行
```
多重包含在绝大多数情况下出现在大型程序中,它往往需要使用很多头文件,因此要发现重复包含并不容易。要解决这个问题,我们可以使用条件编译。如果所有的头文件都像下面这样编写:
```c
#ifndef _HEADERNAME_H
#define _HEADERNAME_H
//(头文件内容)
#endif
```
这样多重包含的危险就被消除了。当头文件第一次被包含时,它被正常处理,符号HEADERNAME_H被定义为1。如果头文件被再次包含,通过条件编译,它的内容被忽略。**符号HEADERNAME_H按照被包含头文件的文件名进行取名,以避免由于其他头文件使用相同的符号而引起的冲突。**
#### 第二种方法
```c
#pragma once(在头文件的最开始加入)
```
\#pragma once方式产生于#ifndef之后。
1. #ifndef方式受C/C++语言标准的支持,不受编译器的任何限制;而#pragma once方式`有些编译器不支持`(较老编译器不支持,如GCC 3.4版本之前不支持#pragmaonce),`兼容性不够好`。
2. `#ifndef可以针对一个文件中的部分代码,而#pragma once只能针对整个文件`。
3. 他也有其最大的弊端:
假如你的某一个头文件有多份拷贝,那么这些文件虽然在逻辑上都是一样的,但是在物理上他们却是不同的,所以当你把这些文件包含的时候,就会发现真的都包含进来了,然后就是编译错误了。
#### 第三种方法 使用_Pragma操作符
C99 标准中新增加了一个和 #pragma 指令类似的 _Pragma 操作符,其可以看做是 #pragma 的增强版,不仅可以实现 #pragma 所有的功能,更重要的是,_Pragma 还能和宏搭配使用。
```
_Pragma("once")
```
#### 总结
另外在某些场景中,考虑到编译效率和可移植性,#pragma once 和 #ifndef 经常被结合使用来避免头文件被重复引入。比如说:
```c
#pragma once
#ifndef _STUDENT_H
#define _STUDENT_H
class Student {`
//......
};
#endif
```
### 文件类型
| 后缀名 | 文件类型 |
| ------------- | -------------------- |
| .i | 预处理之后的文件 |
| .s | 汇编语言的源代码文件 |
| .o或.so或.out | 二进制文件 |
**.c**为后缀的文件,**C语言源代码**文件;
.cpp是C++源代码文件且必须要经过预处理;
**.i** 为后缀的文件,是C源代码文件**执行预处理后生成的文件**;
**.s**为后缀的文件,是编译过程后得到的**汇编语言源代码文件**;
**.o**为后缀的文件,是**汇编后的目标文件**;
#### 库文件
函数库通常以静态库和共享库两种格式存在
- .a代表传统的静态函数库
- .so代表共享函数库
当程序需要使用函数库中的某个函数时,它包含一个声明该函数的头文件,编译器和链接器负责将程序代码和函数库结合在一起以组成一个单独的可执行文件
静态库,也称作归档文件(archive)
使用ar程序和gcc –c命令对函数分别进行编译
##### 静态库小例子1
###### bill.c
```c
#include<stdio.h>
void bill(char *arg){
printf("bill: you passed %s\n",arg);
}
```
###### fred.c
```c
#include<stdio.h>
void fred(int arg){
printf("fred: you passed %d\n",arg);
}
```
###### lib.h
```c
void bill(char *);
void fred(int);
```
###### 命令
```shell
> gcc -c bill.c fred.c
> gcc -c program.c
> gcc -o program program.o bill.o
> ./program
bill: you passed hello,world
> ar crv libfoo.a bill.o fred.o
a - bill.o
a - fred.o
> gcc -o program program.o -L . -lfoo
> ar t libfoo.a # 查看静态库包含内容
bill.o
fred.o
```
##### 静态动态库小例子2
###### add.cpp
```cpp
int my_add (int a,int b){
return a + b;
}
```
###### sub.cpp
```cpp
int my_sub (int a,int b){
return a - b;
}
```
###### mul.cpp
```cpp
int my_mul (int a,int b){
return a * b;
}
```
###### div.cpp
```cpp
int my_div (int a,int b){
return a / b;
}
```
###### abcd.h
```cpp
int my_add(int ,int );
int my_sub(int ,int );
int my_mul(int ,int );
int my_div(int ,int );
```
###### test.cpp
```cpp
#include "abcd.h"
#include <iostream>
using namespace std;
int main(int argc, const char** argv) {
int a = 10,b = 4;
cout<<my_add(a,b)<<endl;
cout<<my_sub(a,b)<<endl;
cout<<my_mul(a,b)<<endl;
cout<<my_div(a,b)<<endl;
return 0;
}
```
###### 命令
```
> g++ -c *.cpp
> ar crv libabcd.a add.o sub.o mul.o div.o
> g++ -o test test.o -L . -labcd
```
###### 动态库的建立
```shell
> g++ -shared -fpic -o ./libabcd.so add.cpp sub.cpp mul.cpp div.cpp # 当前目录下就存在一个libabc.so 的文件
> g++ -o test test.cpp ./libabcd.so # 动态库的编译
# 如果移除了动态库 libabcd.so 那么会报错 ./test: error while loading shared libraries: ./libabcd.so: cannot open shared object file: No such file or directory
```
静态库的缺点:当同时运行多个应用程序,并且它们都使用来自同一函数的多份副本,且在程序文件自身中有多份同样的副本。**这将消耗大量宝贵的内存和磁盘空间**
共享库的保存位置与静态库相同,但共享库有不同的文件名后缀
当一个程序使用共享库时,程序本身不再包含函数代码,而是引用运行时可访问的共享代码。当程序被装载到内存中执行时,函数引用被解析并产生对共享库的调用
共享库的优点:系统只保留共享库的一份副本供多个应用程序同时使用,共享库的更新独立于依赖它的应用程序
**.so库对应于.dll文件,都是在程序运行时加载**
**.a库类似于.lib文件,都包含在可执行程序中**
### gcc 命令
```shell
gcc [options] file ...
```
| 选项 | 作用 |
| ----------- | ---------------------------------- |
| -o <file> | 指定编译后生成的目标文件名为<file> |
| -E | 只做预编译,不汇编,编译和链接 |
| -S | 只编译,不汇编和链接 |
| -c | 编译和汇编,不链接 |
| -g | 添加调试信息给gdb调试使用 |
### 编译过程
#### 预处理(Preprocessing)
**预处理用于将所有的#include头文件以及宏定义替换成其真正的内容**,预处理之后得到的仍然是文本文件,但文件体积会大很多。
> gcc 文件名.c -E -o 文件名.i
#### 编译(Compilation)
这里的编译不是指程序从源文件到二进制程序的全部过程,而是指**将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程**。编译的指令如下:
> gcc 文件名.i -S -o 文件名.s
#### 汇编(Assemble)
**汇编过程将上一步的汇编代码转换成机器码(machine code)**,这一步产生的文件叫做**目标文件**,是二进制格式。
> gcc 文件名.s -c -o 文件名.o
#### 链接(Linking)
**链接过程将多个目标文件以及所需的库文件(.so等)链接成最终的可执行文件(executable file)**。
链接可分为动态链接和静态链接:
- 动态链接使用动态链接库进行链接,生成的程序在执行的时候需要加载所需的动态
库才能运行。动态链接生成的程序小巧,但是必须依赖动态库,否则无法执行。
- Linux 下的动态链接库实际是共享目标文件(shared object),一般是.so 文件,
作用类似于 Windows 下的.dll 文件。
- 静态链接使用静态库进行链接,生成的程序包含程序运行所需要的全部库,可以直
接运行,不过体积较大。
- Linux 下静态库是汇编产生的.o 文件的集合,一般以.a 文件形式出现。
gcc 默认是动态链接,加上-static 参数则采用静态链接。
> gcc 文件名.o -o 文件名.out
### 单个文件的编译过程
```shell
# 1.预处理 只做预编译 不汇编 生成一个文件名为hello_e.c的文件 内容是文本
> gcc hello.c -E -o hello_e.i # hello.c 只有4行 hello_e.c有725行
# 2.编译 只编译,不汇编和链接 无论编译 hello.c 还是 hello_e.c 生成的内容一样 内容是文本格式的汇编代码
> gcc hello_e.i -S -o hello_s.s
# 3.汇编 编译和汇编,不链接 内容是二进制
> gcc hello_s.s -c -o hello_c.o
# 4.链接 生成最终的程序 可以链接多个.o文件
> gcc hello_c.o -o hello.out
> ./hello.out
hello,world
```
#### 部分文件内容展示
##### hello.c
```c
#include<stdio.h>
int main(){
printf("hello,world");
}
```
##### hello_e.c
```
太长了不展示了 一共732行
```
##### hello_s.c
```c
.file "hello.c"
.text
.section .rodata
.LC0:
.string "hello,world"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 10.2.0"
.section .note.GNU-stack,"",@progbits
```
##### hello_c.o 和 hello.out
```shell
都是二进制文件 没必要展示
```
### 多个文件的编译过程
#### 三个方法
##### 方法一 直接编译
```shell
gcc file1.c file2.c file3.c main.c -o out
```
前提是main.c要include其他文件的头文件,来避免main文件中没有声明就使用没定义的函数导致的报错,
##### 方法二 编译成动态共享库
把3个文件编译成动态共享库,再编译main
```shell
> gcc -shared -fPIC file1.c -o libfile1.so
> gcc -shared -fPIC file2.c -o libfile2.so
> gcc -shared -fPIC file3.c -o libfile3.so
> gcc main.c -L. -lfile1 -lfile2 -lfile3 -o out
```
通过so产生的out,依赖so文件,好处是如果file2.c更新了那么只需要替换新的libfile2.so,就可以直接运行原来的out获得新功能,而不需要再次编译出out替换。
##### 方法三静态库的方式
```
gcc -c file1.c
gcc -c file2.c
gcc -c file3.c
ar -rc liballfiles.a file1.o file2.o file3.o
gcc main.c -L. -lallfiles -o out
```
#### 例子
##### 简单方法
###### add.h
```c
int add(int a,int b);
```
###### add.c
```c
#include"add.h"
int add(int a,int b)
{
return a+b;
}
```
###### main.c
```c
#include<stdio.h>
#include"add.h"
int main()
{
int a = 1,b =2;
int c = add(a,b); //这里是对add.c中的add函数的调用
printf("c=%d\n",c);
return 0;
}
```
###### 编译
```
gcc add.c add.h main.c -o add
```
##### 复杂方法
```shell
> gcc -c add.c -o add_c.o -Wall
> gcc -c main.c -o main.o -Wall
> gcc main.o add_c.o -o add -Wall
> ./add
c=3
```
##### -Wall参数
该选项开启所有的警告,例如变量没有赋值,指针没有初始化等等问题。
linux知识补充上