马哥Linux培训课堂笔记(2)

2017-11-14|Categories: Magedu-training|

以下内容主要按照在课堂讲述的顺序记录,有适当整理和延伸,便于回顾复习。

history – 管理命令行历史

语法:

history [-c] [-d offset] [n]
history -anrw [filename]
history -ps arg [arg...]

选项

# 清除内存中记录的命令行历史
history -c

# 删除内存中第10条历史记录
history -d 10

# 显示内存中最近8条命令行历史
history 8

# 把内存中 **当前会话** 的历史追加到历史文件
# 默认操作`~/.bash_history`文件
history -a
history -a new_history.txt

# read all history lines not already read from the history file
# 翻译:从历史文件读取之前(登录时)未能读取的条目到内存
history -n
history -n new_history.txt

# 把历史文件的条目读取到内存
history -r
history -r new_history.txt

# 把内存中记录的历史保存到历史文件
history -w
history -w new_history.txt

# 执行(展开)命令但不记录历史
# 注意如果命令未被反引号「`」或「$()」包围,只会作为字符串输出到stdout
history -p `ls .`

# 把参数记录到历史但不执行命令
history -s ls
# 注意:如果参数被反引号「`」或「$()」包围,内存中记录的条目将是命令展开之后的值!
# 很明显这不是我们想要的结果:
history -s `ls /`

变量

HISTSIZE

定义了内存中保存的命令行历史的数量,配置保存在/etc/profile,CentOS默认值为1000。

HISTFILE

定义了历史文件的路径和名称,默认值为~/.bash_history

HISTFILESIZE

定义了历史文件能保存的条目数量,CentOS默认值为1000。建议和$HISTSIZE相同。

HISTTIMEFORMAT

在历史记录中添加命令执行的时间戳。

HISTTIMEFORMAT='%F %T --> '

从内存中保存到历史文件之后,时间戳会变为注释,时间格式变为Unix时间

HISTIGNORE

定义了哪些命令应该被保存到历史,可以使用冒号分隔多个值,支持通配符。

HISTIGNORE='ls *:cat'

多行复合命令不受此变量影响,会直接存入历史记录。

HISTCONTROL

定义了命令如何保存到历史,可以使用冒号分隔多个值,只接受以下值:

  • ignorespace:忽略(不保存)空格打头的命令。
  • ignoredups:忽略连续的重复命令。默认已设置。
  • ignoreboth:等于ignorespace加上ignoredups
  • erasedups:当前命令存入内存时,之前保存的所有相同命令将被删除。

多行复合命令不受此变量影响,会直接存入历史记录。

FHS

The Filesystem Hierarchy Standard (FHS) is a reference describing the conventions used for the layout of a UNIX system. It has been made popular by its use in Linux distributions, but it is used by other UNIX variants as well. The Linux Standard Base (LSB) refers to it as a standard.

https://wiki.linuxfoundation.org/lsb/fhs

翻译:

文件系统层次结构标准(FHS)是描述用于UNIX系统布局的约定的参考。它在Linux发行版中被广泛使用,但也被其他UNIX变种所使用。Linux标准库(LSB)将其称为标准。

by Google Translate

FHS规定,以下是根目录/下必备的一级目录

FHS整体可以形象化表示为下图的样子:

LSB

The Linux Standard Base (LSB) is a Linux Foundation (LF) project to develop, through consensus, a set of standards that will increase compatibility among Linux distributions and enable conforming products to work with any compliant system.

https://wiki.linuxfoundation.org/lsb/lsb-charter

翻译:

Linux标准库(LSB)是一个Linux基金会(LF)项目,旨在通过共识开发一套标准,以提高Linux发行版之间的兼容性,并使符合标准的产品能够与任何兼容的系统一起工作。

by Google Translate

其它重要的一级目录

/proc/

/proc is very special in that it is also a virtual filesystem. It's sometimes referred to as a process information pseudo-file system. It doesn't contain 'real' files but runtime system information (e.g. system memory, devices mounted, hardware configuration, etc). For this reason it can be regarded as a control and information centre for the kernel. In fact, quite a lot of system utilities are simply calls to files in this directory. For example, lsmod is the same as cat /proc/modules while lspci is a synonym for cat /proc/pci. By altering files located in this directory you can even read/change kernel parameters (sysctl) while the system is running.

The most distinctive thing about files in this directory is the fact that all of them have a file size of 0, with the exception of kcore, mtrr and self.

http://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html

翻译:

/proc是非常特殊的,它也是一个虚拟文件系统。它有时被称为进程信息伪文件系统。它不包含“真实”文件,而是包含运行时系统信息(例如系统内存,安装的设备,硬件配置等)。由于这个原因,它可以被看作是内核的控制和信息中心。实际上,相当多的系统工具只​​是调用这个目录中的文件。例如,lsmodcat /proc/modules是一样的,lspcicat /proc/pci的同义词。通过修改位于这个目录下的文件,你甚至可以在系统运行的时候读取/修改内核参数(sysctl)。

这个目录中最有特色的事情是文件大小都是0,除了kcoremtrrself之外。

by Google Translate

常用的文件:

  • 查看磁盘分区信息:cat /proc/partitions
  • 查看CPU信息:cat /proc/cpuinfo
  • 查看内存信息:cat /proc/meminfo

/sys/

通常存放硬件相关信息。可以利用此目录快速添加虚拟SCSI磁盘:

echo '- - -' > /sys/class/scsi_host/host0/scan
# or
echo '- - -' > /sys/class/scsi_host/host2/scan

注意:不要在生产环境使用此方法。

lost+found

这是ext文件系统家族特有的目录,每个分区都有自己的lost+found/目录。

/misc/ & /net/

这是autofs服务开启后自动生成的目录,CentOS 6默认开启了autofs,CentOS 7默认没有开启,建议开启。开启autofs后,光盘默认被挂载到/misc/cd/目录,但autofs的巧妙之处在于,如果开机之后不执行cd /misc/cd,当执行ls -a /misc时,将看不到cd目录。

autofs

autofs is a program for automatically mounting directories on an as-needed basis. Auto-mounts are mounted only as they are accessed, and are unmounted after a period of inactivity. Because of this, automounting NFS/Samba shares conserves bandwidth and offers better overall performance compared to static mounts via fstab.

https://help.ubuntu.com/community/Autofs

翻译:

autofs是一个根据需要自动挂载目录的程序。目录自动挂载就是仅在被访问时挂载,并且在一段时间不活动后被卸载。因此,与通过fstab进行静态挂载相比,自动挂载NFS/Samba共享目录会节省带宽并提供更好的整体性能。

文件名大小写

通常我们说「Windows、macOS的文件名不区分大小写,Linux区分大小写」,这是不对的。实际上,是操作系统使用的文件系统决定了是否区分大小写,例如,在Linux系统中,ext/xfs文件系统区分大小写,而vfat文件系统不区分大小写。

工作目录(working directory)

  • 每执行一次cd命令就会改变工作目录。
  • cd -可以回到(也只能回到)上一个工作目录。
    • 具体的路径保存在$OLDPWD变量中。
    • 直接修改$OLDPWD变量可以改变cd -的执行结果。
  • pwd命令可以查看当前工作目录。
    • 具体的路径保存在$PWD变量中。
    • 直接修改$PWD变量不能改变pwd的执行结果,但可以改变命令提示符显示的目录名。

时间戳(atime、ctime、mtime)

  • atime = access time,文件最近一次被访问的时间。
  • ctime = change time,文件元数据(inode)最近一次被修改的时间。
  • mtime = modification time,文件内容最近一次被修改的时间。

备注:「文件内容」就是用户可以看到的内容,比如用echo 'hello world.' > sample.txt生成的文件的内容就是「hello world.」

设置不同命令显示不同时间

  • stat命令可以同时显示atime、ctime、mtime。
  • ls -l默认显示mtime,可以通过--time=ctime选项显示ctime,atime同理。
  • touch默认同时把atime和mtime更新到当前时间,但因为时间戳属于文件的元数据,所以操作系统会随之更新ctime。

relatime

如果每次访问文件都更新atime,会给访问量巨大的系统带来巨大的磁盘I/O,严重影响性能。因此,从RHEL 6开始,所有挂载的文件系统都默认启用了relatime功能:

The kernel used in Red Hat Enterprise Linux 6 supports another alternative — relatime. relatime maintains atime data, but not for each time that a file is accessed. With this option enabled, atime data is written to the disk only if the file has been modified since the atime data was last updated (mtime), or if the file was last accessed more than a certain amount of time ago (by default, one day).

By default, all file systems are now mounted with relatime enabled.

https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/power_management_guide/relatime

简单来说,relatime功能仅在满足以下任一条件时更新atime:

  • atime比mtime或ctime更旧。
  • atime相距当前时间超过1天。

ls – 列出文件或目录

仅显示目录(包括隐藏目录)

ls -d */ .[!.]*/

仅显示文件(包括隐藏文件)

# `-p`选项在目录后添加斜线`/`
ls -ap | grep -v /

仅显示隐藏的文件和目录

ls默认只显示非隐藏文件和目录(不是.打头),如果要反其道而行之,只显示隐藏文件和目录,可以使用以下方法:

la -ad .[!.]*

# 或者使用`-I`选项忽略满足预设条件(pattern)的项目
# pattern必须使用引号包围
ls -aI "[^.]*"

排序选项

  • -U:根据文件或目录的创建时间排序。
  • -X:根据扩展名排序。
  • -S:根据文件大小排序。
  • -t:根据时间戳排序(默认是mtime)。
    • -u: atime
    • -c: ctime

cp – 复制文件或目录

常用选项

选项 用途 备注
-a
--archive
等于-dR --preserv=all 复制特殊文件必须添加:
cp -a /dev/zero ~
-d 等于--no-dereference --preserve=links 复制软连接本身,不复制其指向的真实文件
-R
-r
--recursive
递归复制 复制目录时必须添加
-p 等于--preserv=mode,ownership,timestamps
-u
--update
仅从源地址复制比目标地址更新的文件,或是目标地址缺少的文件
--backup=numbered 如果目标文件已存在,将其备份为数字后缀(.~1~)后再复制
-f
--force
如果不能打开已有的目标文件,将其删除并尝试再次复制 -n选项一起使用会失效
-n 不覆盖已有同名文件,即同名的源文件不会被复制 放在前面的-i选项会失效
-i
--interactive
提示是否覆盖目标目录同名文件 放在前面的-n选项会失效

强制覆盖已有文件

普通用户即使对目标目录(destination)有写入权限,cp命令默认也不会覆盖目标目录中owner为其他用户的同名文件,如果需要强制覆盖,需要添加-f选项。

# 特意删除了root用户命令提示符末尾的#号,否则后续命令会被当做注释显示

# 创建测试目录
[root@centos7 ~] mkdir -p ~liyang/testing/dir{1,2}

# 修改测试目录owner
[root@centos7 ~] chown -R liyang.liyang ~liyang/testing

# 检查测试目录权限
[root@centos7 ~] ll -d ~liyang/testing ~liyang/testing/*
drwxr-xr-x 4 liyang liyang 30 Nov 12 09:13 /home/liyang/testing
drwxr-xr-x 2 liyang liyang  6 Nov 12 09:13 /home/liyang/testing/dir1
drwxr-xr-x 2 liyang liyang  6 Nov 12 09:13 /home/liyang/testing/dir2

# 用root身份创建测试文件a
[root@centos7 ~] echo 'I am file a which made by root.' > ~liyang/testing/dir1/a

# 切换到普通用户liyang
[root@centos7 ~] su - liyang

# 用liyang身份创建测试文件b
[liyang@centos7 ~]$ cd testing/
[liyang@centos7 testing]$ echo 'I am file b which made by liyang.' > dir2/b

# 列出测试目录所有文件
[liyang@centos7 testing]$ ll -R dir1 dir2
dir1:
total 4.0K
-rw-r--r-- 1 root root 32 Nov 12 09:24 a

dir2:
total 4.0K
-rw-rw-r-- 1 liyang liyang 57 Nov 12 09:25 b

# cp不加选项尝试覆盖,提示「权限被拒绝」
[liyang@centos7 testing]$ cp dir2/b dir1/a
cp: cannot create regular file ‘dir1/a’: Permission denied

# 加上`-f`选项强制覆盖,操作成功
[liyang@centos7 testing]$ cp -f dir2/b dir1/a

# 再次列出测试目录所有文件,文件a已经被覆盖
[liyang@centos7 testing]$ ll -R dir1 dir2
dir1:
total 4.0K
-rw-rw-r-- 1 liyang liyang 57 Nov 12 10:06 a

dir2:
total 4.0K
-rw-rw-r-- 1 liyang liyang 57 Nov 12 09:25 b

为什么普通用户能覆盖root用户的文件

覆盖已有文件实际分为两步:

  1. 删除已有文件。
  2. 在原来的位置创建同名的新文件。

在上一小节的操作中,看起来就是普通用户liyang删除了owner为root的文件a,真的是这样吗?Linux权限管理模型不是规定了root用户拥有最高权限吗,为什么普通权限的用户能删除root用户的文件?

其实,真实的情况是,不是普通用户删除了文件,而是系统删除的,用户仅仅是从自己的目录中移除文件。

The user didn't delete the file, the system did. The user merely removed the file from his own directory.

https://superuser.com/questions/369493/why-a-non-root-user-can-delete-files-created-by-root

但是,从目录移除文件会导致文件的连接数减少,

Removing a file from a directory (called 'unlinking') is an operation on the directory. Unlinking a file reduces its reference count.

系统会自动删除连接数为0的文件,不管这个文件的拥有者是谁都是同样的待遇。

The system deletes files automatically when their reference counts drops to zero. The owner of the file doesn't matter.

说白了,普通用户并没有「以下犯上」的实力,他仅仅是借了系统的东风,狐假虎威而已。

将root作为复制文件的owner

要想让复制的文件的owner是root,只能由root账号来执行复制操作,普通用户即使添加--preserv=all也不行。

Only processes with an effective user ID equal to the user ID of the file or with appropriate privileges may change the ownership of a file.

http://pubs.opengroup.org/onlinepubs/009695399/functions/chown.html

使用tar命令打包、取出文件同样如此。

mknod – 手工创建设备文件

# 手工创建字符设备
mknod /app/zero c 1 5

# 手工创建管道
mknod /app/pipefile p

rename – 批量重命名

语法:rename from to file...

假如我有file1file100这100个文件,ls -a默认的按名称排序完全不符合我的预期:

我希望把文件名包含的数字改为3位,从小到大排序:

借助rename只需要两步:

# 给file后面只有1位数字的文件添加一个0
rename file file0 file?

# 给file后面只有2位数字的文件添加一个0
rename file file0 file??

支持正则表达式的rename 2018-01-16

网络上许多教程使用的是支持正则表达式的rename(Ubuntu自带),而RHEL/CentOS系统自带的rename工具不支持正则表达式语法,这既让它的实用性大打折扣,也让不了解内情的人照着教程练习时满头雾水、饱受挫折。

其实,在CentOS系统上,同样可以使用支持正则表达式的rename,这个工具只有一个单独的Perl文件,下载到CentOS上即可运行:

cd /usr/local/bin
mkdir prename
git clone https://github.com/ap/rename.git prename
ln -s prename/rename rename

macOS: brew install rename

The macOS version from http://plasmasturm.org/code/rename

因为系统自带了/usr/bin/rename,必须保证/usr/local/bin$PATH变量中处于/usr/bin的前面:

export PATH="/usr/local/bin:$PATH"

此时就可以使用rename --man查看完整的帮助文件。如果用这个rename完成之前的批量重命名工作,需要这样:

# -n = --just-print = --dry-run
# -v = --verbose
rename -nv 's/([0-9])/00\1/' file[0-9]
rename -nv 's/([0-9]{2})/0\1/' file[0-9][0-9]

-n选项可以显示模拟执行的结果,让用户可以在确认命令符合预期之后,再真正执行,这在批量重命名的时候是非常有必要的。

上面这个例子并不能体现支持正则表达式的rename的强大,但对于许多复杂情况,有一个支持正则表达式的工具,将大有裨益。

rm – 移除(删除)文件

和Windows不一样,Linux删除文件时没有「回收站」的概念,所以rm命令绝对是Unix/Linux系统最危险的命令之一,我自己就有过在月黑风高、睡眼迷离的情况下输入rm -rf /*删除整个macOS系统(没有写错,确实是macOS)的惨痛经历。

因此,CentOS 6和7默认禁用了rm -rf /命令:

但让人不理解的是,rm -rf /*并没有被禁用,难免有种「为山九仞,功亏一篑」的感觉。于是,为了给自己留条后路,我做了如下配置:

vim ~/.bashrc

# 注释掉下面这一行,避免冲突
# alias rm='rm -i'

# 创建一个Bash函数`rm`,调用该函数的时候,将把函数后面所有参数移动到`/tmp/trash`
function rm {
    mv -- "$@" /tmp/trash 2>/dev/null
    echo "$# items have been moved to /tmp/trash"
}

source ~/.bashrc

下次执行rm命令时,其实是调用我自定义的rm函数,把所有预备删除的项目移动到/tmp/trash目录。

Leave A Comment