本文主要内容:FHS,文本查看、文件与目录管理命令,Bash特性,包括管道、重定向、命令历史、别名、变量等,以及Globbing,用户与权限管理。
计算机实质上就是处理数据的设备,这些数据在存储介质中是以文件(File)的形式存在的,而具体该如何保存,以及如何对硬件进行逻辑抽象管理,使其可以保存,就是文件系统的功能之一。
计算机的文件系统是一种存储和组织计算机数据的方法,它使得对其访问和查找变得容易,文件系统使用文件和树形目录的抽象逻辑概念代替了硬盘和光盘等物理设备使用数据块的概念,用户使用文件系统来保存数据不必关心数据实际保存在硬盘(或者光盘)的地址为多少的数据块上,只需要记住这个文件的所属目录和文件名。在写入新数据之前,用户不必关心硬盘上的那个块地址没有被使用,硬盘上的存储空间管理(分配和释放)功能由文件系统自动完成,用户只需要记住数据被写入到了哪个文件中。
广义角度来讲,Linux系统是有底层的Kernel与上层Application组成。其在计算机启动之前也是以文件的形式存在于外存中,而这些文件保存在外存(以下称为磁盘)的何处位置,Linux的众多发行组织均可以自定义。如此对于用户的学习和使用而言是极为不便的,亦不利于其传播。鉴于此,Linux Foundation(Linux基金会)定义了Linux发行版中,文件所应该遵从的组织方式,即FHS(Filesystem Hierarchy Standard,文件系统层级标准) 1
该规范说明了系统上应该存在哪些目录,以及不同文件所应该保存的位置,以下为简要说明
目录 | 说明 |
---|---|
/bin | 所有用户可用的基本命令程序文件 |
/boot | 引导加载器必须用到的各静态文件,如kernel、ramfs(initrd),以及grub(bootloader)等 |
/dev | 设备文件与特殊文件 |
/etc | 系统程序的静态配置文件 |
/home | 普通的家目录的集中位置;一般每个普通用户的家目录默认为此目录下与用户名同名的子目录 |
/lib | 为系统启动或根文件系统上的应用程序(/bin,/sbin等)提供共享库,以及为内核提供内核模块 |
/lib64 | 特定字长系统上的库文件,如64位系统上为/lib64 |
/media | 挂载点目录,通常用来挂载移动设备 |
/mnt | 挂载点目录,通常挂载额外的临时文件系统 |
/opt, /options | 附加应用程序的安装位置,可选 |
/proc | 虚拟文件系统,用于为内核及进程存储其相关信息 |
/root | 管理员的家目录,可选 |
/run | 存放动态的,不持久的应用程序运行数据 |
/sbin | 供管理员使用的工具程序 |
/srv | 系统上运行的服务用到的数据 |
/sys | sysfs虚拟文件系统提供了一种比proc更为理想的访问内核数据的途径;其主要作用在于为管理Linux设备提供一种统一模型的的接口 |
/tmp | 临时文件 |
/usr | 全局共享的只读数据路径 |
/var | 频繁发生变化的文件 |
/misc | 备用目录,可选 |
/selinux | SELinux(Security Enhanced Linux)相关的安全策略等信息的存储位置 |
[root@localhost ~]# ls /
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
usr意为universal shared read-only file,全局共享只读文件,即该目录可以在所有遵循FHS的主机间共享(只读)
目录 | 说明 |
---|---|
/usr/include | C程序头文件 |
/usr/bin | 普通用户命令 |
/usr/sbin | 供管理员使用的命令 |
/usr/lib | 库文件 |
/usr/lib |
特定字长系统上的库文件,如64位系统上为/usr/lib64 |
/usr/share | 命令手册也和自带文档等架构特有的文件的存储位置,例如doc, man等 |
/usr/X11R6 | X-Window程序的安装位置(可选) |
/usr/src | 程序源码文件的存储位置 |
/usr/local | 第三方软件的安装路径,也是一个独立层级 |
/usr/games | 游戏或教育程序 |
该目录也是一个独立的层级,其中有bin,sbin等目录,如下内容引用自 https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#USRLOCALLOCALHIERARCHY
The /usr/local hierarchy is for use by the system administrator when installing software locally. It needs to be safe from being overwritten when the system software is updated. It may be used for programs and data that are shareable amongst a group of hosts, but not found in /usr.
Locally installed software must be placed within /usr/local rather than /usr unless it is being installed to replace or upgrade software in /usr.
Directory | Description |
---|---|
bin | Local binaries |
etc | Host-specific system configuration for local binaries |
games | Local game binaries |
include | Local C header files |
lib | Local libraries |
man | Local online manuals |
sbin | Local system binaries |
share | Local architecture-independent hierarchy |
src | Local source code |
/var contains variable data files. This includes spool directories and files, administrative and logging data, and transient and temporary files.
Some portions of /var are not shareable between different systems. For instance, /var/log, /var/lock, and /var/run. Other portions may be shared, notably /var/mail, /var/cache/man, /var/cache/fonts, and /var/spool/news.
/var is specified here in order to make it possible to mount /usr read-only. Everything that once went into /usr that is written to during system operation (as opposed to installation and software maintenance) must be in /var.
If /var cannot be made a separate partition, it is often preferable to move /var out of the root partition and into the /usr partition. (This is sometimes done to reduce the size of the root partition or when space runs low in the root partition.) However, /var must not be linked to /usr because this makes separation of /usr and /var more difficult and is likely to create a naming conflict. Instead, link /var to /usr/var.
Applications must generally not add directories to the top level of /var. Such directories should only be added if they have some system-wide implication, and in consultation with the FHS mailing list.2
目录 | 说明 |
---|---|
/var/log | 日志目录及文件 |
/var/lock | 锁文件 |
/var/run | 运行中的进程相关的数据,通常用于存放进程的PID文件 |
/var/cache | 应用程序缓存数据目录 |
/var/lib | 应用程序状态信息数据 |
/var/local | 专用于为/usr/local下的应用程序存储可变数据 |
/var/opt | 专用于为/opt下的应用程序存储可变数据 |
/var/spool | 应用程序数据池 |
/vat/tmp | 保存系统两次重启之间产生的临时数据 |
/sys 下的子目录 | 所包含的内容 |
---|---|
/sys/devices | 这是内核对系统中所有设备的分层次表达模型,也是 /sys 文件系统管理设备的最重要的目录结构,下文会对它的内部结构作进一步分析; |
/sys/dev | 这个目录下维护一个按字符设备和块设备的主次号码(major:minor)链接到真实的设备(/sys/devices下)的符号链接文件,它是在内核 2.6.26 首次引入; |
/sys/bus | 这是内核设备按总线类型分层放置的目录结构, devices 中的所有设备都是连接于某种总线之下,在这里的每一种具体总线之下可以找到每一个具体设备的符号链接,它也是构成 Linux 统一设备模型的一部分; |
/sys/class | 这是按照设备功能分类的设备模型,如系统所有输入设备都会出现在 /sys/class/input 之下,而不论它们是以何种总线连接到系统。它也是构成 Linux 统一设备模型的一部分; |
/sys/block | 这里是系统中当前所有的块设备所在,按照功能来说放置在 /sys/class 之下会更合适,但只是由于历史遗留因素而一直存在于 /sys/block, 但从 2.6.22 开始就已标记为过时,只有在打开了 CONFIG_SYSFS_DEPRECATED 配置下编译才会有这个目录的存在,并且在 2.6.26 内核中已正式移到 /sys/class/block, 旧的接口 /sys/block 为了向后兼容保留存在,但其中的内容已经变为指向它们在 /sys/devices/ 中真实设备的符号链接文件; |
/sys/firmware | 这里是系统加载固件机制的对用户空间的接口,关于固件有专用于固件加载的一套API,在附录 LDD3 一书中有关于内核支持固件加载机制的更详细的介绍; |
/sys/fs | 这里按照设计是用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点,但目前只有 fuse,gfs2 等少数文件系统支持 sysfs 接口,一些传统的虚拟文件系统(VFS)层次控制参数仍然在 sysctl (/proc/sys/fs) 接口中中; |
/sys/kernel | 这里是内核所有可调整参数的位置,目前只有 uevent_helper, kexec_loaded, mm, 和新式的 slab 分配器等几项较新的设计在使用它,其它内核可调整参数仍然位于 sysctl (/proc/sys/kernel) 接口中 ; |
/sys/module | 这里有系统中所有模块的信息,不论这些模块是以内联(inlined)方式编译到内核映像文件(vmlinuz)中还是编译为外部模块(ko文件),都可能会出现在 /sys/module 中: ● 编译为外部模块(ko文件)在加载后会出现对应的 /sys/module/ ● 编译为内联方式的模块则只在当它有非0属性的模块参数时会出现对应的 /sys/module/ ●● 如 /sys/module/printk/parameters/time 这个可读写参数控制着内联模块 printk 在打印内核消息时是否加上时间前缀; ●● 所有内联模块的参数也可以由 “ ● 没有非0属性参数的内联模块不会出现于此。 |
/sys/power | 这里是系统中电源选项,这个目录下有几个属性文件可以用于控制整个机器的电源状态,如可以向其中写入控制命令让机器关机、重启等。 |
/sys/slab (对应 2.6.23 内核,在 2.6.24 以后移至 /sys/kernel/slab) | 从2.6.23 开始可以选择 SLAB 内存分配器的实现,并且新的 SLUB(Unqueued Slab Allocator)被设置为缺省值;如果编译了此选项,在 /sys 下就会出现 /sys/slab ,里面有每一个 kmem_cache 结构体的可调整参数。对应于旧的 SLAB 内存分配器下的 /proc/slabinfo 动态调整接口,新式的 /sys/kernel/slab/ |
如:
[root@localhost ~]# ls -l /dev
total 0
crw-rw----. 1 root video 10, 175 Dec 28 22:21 agpgart
crw-------. 1 root root 10, 235 Dec 28 22:21 autofs
drwxr-xr-x. 2 root root 180 Dec 28 22:21 block
drwxr-xr-x. 2 root root 80 Dec 28 22:21 bsg
crw-------. 1 root root 10, 234 Dec 28 22:21 btrfs-control
drwxr-xr-x. 3 root root 60 Dec 28 22:21 bus
lrwxrwxrwx. 1 root root 3 Dec 28 22:21 cdrom -> sr0
drwxr-xr-x. 2 root root 100 Dec 28 22:21 centos
drwxr-xr-x. 2 root root 3060 Dec 28 22:21 char
crw-------. 1 root root 5, 1 Dec 28 22:21 console
lrwxrwxrwx. 1 root root 11 Dec 28 22:21 core -> /proc/kcore
drwxr-xr-x. 6 root root 140 Dec 28 22:21 cpu
cp以为copy,即复制,用于复制文件或目录,格式:
cp SRC... DEST
若SRC是一个文件
若DEST不存在:创建此文件,并复制源文件的数据流至DEST中
若DEST存在:覆盖,此时建议使用-i选项
若DEST存在,且是个目录:复制源至目标目录中并保持源文件名
若SRC有多个文件
若目标存在,且是一个文件,报错
若目标存在,且是一个目录:复制个文件至目标目录中,并保持原名
若目标不存在,报错
若SRC是只有一个且是目录(cp目录默认只复制文件,不会复制目录)
若目标是一个文件且存在,报错
若目标不存在:创建新目录
若目标存在且是目录:复制源目录至目标目录中,且保持原名
常用选项
选项 | 描述 |
---|---|
-R, -r, --recursive | copy directories recursively,递归复制一个目录及其目录下所有位文件(包括子目录) |
-f, --force | 强行覆盖 |
-i, --interactive | 交互式复制,如提醒用户是否覆盖已存在的数据 |
-p | same as --preserve=mode(权限),ownership(属主属组),timestamps(时间戳),保留文件的属主、属组、权限以及时间戳 |
-a, --archive | same as -dR,archive(归档),保留文件所有属性,常用于备份 |
-d,–no-dereference,–preserv=links | 不追踪符号链接 |
–preserve[=ATTR_LIST] | ATTR_LIST - - - - mode:权限 - - - - ownership:从属关系(属主属组) - - - - timestamps:时间戳 - - - - links:链接属性 - - - - xattr:扩展属性 - - - - context:安全上下文 - - all:以上所有 |
-L, --dereference | always follow symbolic links,复制链接指向的文件(默认如此) |
-P, --no-dereference | never follow symbolic links in SOURCE ,保持链接 |
-d | same as --no-dereference --preserve=links,当源文件为连接文件时,复制链接文件本身而非其指向的源文件 |
mv意为move,即移动,可用于移动文件位置,或文件重命名。使用格式如下:
mv [OPTION]... SOURCE... DIRECTORY
如果源和目标的路径相同,只是文件名不同,则为重命名
[OPTION]
-i prompt before overwrite 提示覆盖(默认管理员命令别名中存在)
-f do not prompt before overwriting 强制覆盖,不提示
-t, --target-directory=DIRECTORY
格式: mv -t DEST SRC
mv可以直接移动目录,而无需-r选项
install即安装,可用于复制文件并定制其属性,常用格式
单文件复制
install [OPTION]... [-T] SOURCE DEST
把多个文件复制到一个目录中:
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
创建目录
install [OPTION]... -d DIRECTORY...
[OPTION]
-m=MODE 指定权限,默认为755
-o=OWNER 指定属主
-g=GROUP 指定属组
mktemp意为make temporary,可创建临时文件或目录。常见用法如下:
mktemp [OPTION]... [TEMPLATE]
[OPTION]
-d 创建临时目录
[TEMPLATE]
指定要创建的临时文件或目录的名称,需要至少包含3个“X”
如:
[root@localhost ~]# mktemp /tmp/mytmp
mktemp: too few X's in template ‘/tmp/mytmp’
[root@localhost ~]# mktemp /tmp/mytmpXXXX
/tmp/mytmp8wQ7
[root@localhost ~]# mktemp /tmp/mytmpXXXXXXXXX
/tmp/mytmp6CwrEUrFN
[root@localhost ~]# mktemp /tmp/mytmpX2X3X4X5X6X
mktemp: too few X's in template ‘/tmp/mytmpX2X3X4X5X6X’
mkdir即make directory,创建空目录,用法如下:
mkdir [OPTION]... DIRECTORY...
[OPTION]
-p, --parents
no error if existing, make parent directories as needed
参数中路径的最后一个节点才是要创建的目录,即路径基名才为命令的作用对象
基名之前的路径须存在,若路径不存在可使用该选项创建
-v, --verbose
print a message for each created directory
-m MODE 创建目录时直接指定权限
rmdir意为remove directory,用于移除一个空目录
rmdir [OPTION]... DIRECTORY...
[OPTION]
-p, --parents Remove DIRECTORY and its ancestors
删除某目录后,若其父目录为空,则一并删除,依次类推
-v 显示详细信息
tree意为树,我们通常将Linux目录结构称为倒置的树状结构,使用该命令可展示该结构,命令参数:
参数 | 说明 |
---|---|
-L level | 指定显示层级数目 |
-d | 只显示目录 |
-P pattern | 只显示由指定的pattern匹配到的路径 |
如:
[root@localhost ~]# tree -dL 1 /
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib64 -> usr/lib64
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── srv
├── sys
├── tmp
├── usr
└── var
19 directories
rm为remove,可移除文件或目录,该命令常用选项较少,但非常危险,请谨慎操作:
由于管理员使用该命令风险较高,故mv、rm、cp等默认都为管理员用户设置了命令别名4,用作提醒。
另外,建议所有不用的文件建议不要直接删除,而是移动至某个专用目录(模拟回收站)
cat意为concatenate,连接文件并将其打印到标准输出,其使用格式为:
cat [OPTION]... [FILE]...
OPTION | 描述 |
---|---|
-E | 显示行结束符$ |
-s | 将多个连续的空白行显示为一行 |
-n | 显示行号 |
-v | 显示非打印字符 |
-e | 相当于-vE |
如,欲查看/etc/fstab文件内容:
[root@localhost /]# cat /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Dec 19 20:12:26 2018
#
# Accessible filesystems, by reference, are maintained under '/dev/disk'
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
#
/dev/mapper/centos-root / xfs defaults 0 0
UUID=a8cac4fb-841a-421d-ba11-ea7eee1c57bc /boot xfs defaults 0 0
/dev/mapper/centos-home /home xfs defaults 0 0
/dev/mapper/centos-swap swap swap defaults 0 0
与cat命令相似,只是默认按行逆序显示
[root@localhost /]# tac /etc/fstab
/dev/mapper/centos-swap swap swap defaults 0 0
/dev/mapper/centos-home /home xfs defaults 0 0
UUID=a8cac4fb-841a-421d-ba11-ea7eee1c57bc /boot xfs defaults 0 0
/dev/mapper/centos-root / xfs defaults 0 0
#
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info
# Accessible filesystems, by reference, are maintained under '/dev/disk'
#
# Created by anaconda on Wed Dec 19 20:12:26 2018
# /etc/fstab
#
head意为头,顾名思义,可查看文本文件的前几行,默认为10
head [OPTION]... [FILE]...
[OPTION]
-c #: 指定获取前#字节
-n #: 指定获取前#行
-#:n可省略
如:
[root@localhost ~]# head -5 /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Dec 19 20:12:26 2018
#
[root@localhost ~]# head -c 50 /etc/fstab
#
# /etc/fstab
# Created by anaconda on Wed Dec 1[root@localhost ~]#
该命令在执行完成后不会自动换行
tail即尾部,同样,可用于查看文本文件的末尾几行,默认为10
tail [OPTION]... [FILE]...
[OPTION]
-c #: 指定获取后#字节
-n # 显示后#行
-#:n可省略
-f 显示文件尾部,不退出,等待显示后续追加至此文件的新内容,通常用来监视日志
more意为更多的,其命令手册解释为: file perusal filter for crt viewing,可用于显示文本文件,命令使用方式同man命令。与之不同的是,该命令在文件显示至尾部后,将会自动退出。
less命令的同发与man命令相同,这里不再赘述。
bash会保存的过去曾经执行过的命令,在当前shell进程中,保存在内存缓冲区中;
在用户的家目录下有一个**.bash_history**的隐藏文件,在用户正常退出时,内存缓冲区中的命令历史会追加到该文件中
用户在登陆时,系统会读取 ~/.bash_history 文件中记录下的命令
使用上下箭头键可以翻看此前曾经执行过的命令
可通过使用history命令查看命令历史
按键 | 操作 |
---|---|
!n | 执行命令历史中的第n条命令 |
!-n | 执行命令历史中倒数第n条命令 |
!! | 执行上一条命令 |
!STRING | 执行命令历史中最近一个以STRING开头的命令(命令的重复执行有时候需要依赖于幂等性) |
!$ | 引用上一个命令的最后一个参数 |
ESC, . | (按下ESC后,松开按.),引用上一个命令的最后一个参数 |
Alt+. | 引用上一个命令的最后一个参数(远程终端可能不支持) |
history,即历史,Display the history list with line numbers,用法:
history [-c] [-d offset] [n]
history -anrw [filename]
history -ps arg [arg...]
参数
-c 清空命令历史
-r 从文件读取命令历史到历史列表中
-w 把历史列表中的命令追加到历史文件中
-d OFFSET [n] 删除指定位置的命令
-a 追加当前会话的命令历史到历史文件中
# 显示历史中最近的#条命令
我们在bash中输入时,可以通过敲Tab键来对我们的键入进行补全操作。
按Tab可以补全以当前输入字符串开头的路径,若有多个,按两次Tab可以显示所有以该字符串开头的路径,若没有指出路径,则为当前目录。
该操作由bash搜索文件系统实现
shell程序在接受到用户执行命令的请求,分析完成后,最左侧的字符串会被当做命令。在其搜索命令时,先搜索内部命令,而后将根据PATH坏境变量这设定的目录,自左而右逐个搜索目录下的文件名。
按Tab可以补全以当前输入字符串开头的命令,若有多个,按两次Tab可以显示所有以该字符串开头的命令,在PATH环境变量下搜索补全。
PATH环境变量是一组有冒号分隔的路径:
[root@localhost ~]# echo $PATH
/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
由于进程在发起之前,其程序文件都是保存于计算机上的某位置,而我们之所以在键入命令时不必每次都输入命令的完整路径(即位置)就可以将其发起为一个进程(即运行命令),就是因为PATH环境变量。
bash的*花括号展开特性可承载一个以逗号分隔的路径列表,并能够将其展开为多个,如:
[root@localhost ~]# mkdir -pv /mnt/test/{x/m,y}
mkdir: created directory ‘/mnt/test’
mkdir: created directory ‘/mnt/test/x’
mkdir: created directory ‘/mnt/test/x/m’
mkdir: created directory ‘/mnt/test/y’
以上命令同
[root@localhost ~]# mkdir -p /mnt/test/x/m
[root@localhost ~]# mkdir -p /mnt/test/y
[root@localhost ~]# mkdir -p /mnt/test/z
再如,使用展开用创建/tmp/test/a_b,a_c,d_b,d_c四个目录:
mkdir -pv /mnt/test/{a,d}_{b,c}
按键 | 说明 |
---|---|
Ctrl+a | 跳到命令行首 |
Ctrl+e | 跳到命令行尾 |
Ctrl+u | 删除光标至命令行首的内容 |
Ctrl+k | 删除光标至命令行尾的内容 |
Ctrl+← | 向左跳转一个单词 |
Ctrl+→ | 向右跳转一个单词 |
Ctrl+l | 清屏,相当于clear命令 |
Ctrl+c | 取消或终止 |
Ctrl+z | 将当前命令送至后台,使用fg命令调回上次送至后台的进程 |
在我们经常使用某些冗长或不变记忆的命令时,可为其定义命令别名。
如在Windows中,cls为清空屏幕命令,而在Linux中为clear,若更习惯使用“cls”,则可将cls定义为clear的别名,如此,在执行cls时,bash将执行clear;
再如,我们若需要经常编辑/etc/sysconfig/network-scripts/ifcfg-eno16777736文件时,在输入时比较繁琐,可将其定义为别名,使用alias命令:
[root@localhost ~]# alias vimnet='vim /etc/sysconfig/network-scripts/ifcfg-eno16777736'
如此,在运行vimnet后,将等同于键入了vim /etc/sysconfig/network-scripts/ifcfg-eno16777736。
不带参数的alias命令可用于查看当前shell已经生效的名别名:
[root@localhost ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias vimnet='vim /etc/sysconfig/network-scripts/ifcfg-eno16777736'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
上文有提到,rm等命令已经默认为管理员用户设置了命令别名,这里可以查询。
若命令别名设置的与原命令相同,可在命令前加“\”(反斜线)来执行原命令。
若要撤销设定的命令别名,可使用unalias命令:
unalias COMMAND_ALIAS
撤销命令别名时只需指定别名即可
常用选项
使用alias设定的命令别名进队当前shell进程有效,可以在shell的配置文件中定义,使别名永久有效:
若要使其立即生效,指定bash重新读取配置文件即可:
source /PATH/TO/CONFIG_FILE
该命令也可简写为.
. /PATH/TO/CONFIG_FILE
引号,即为引用之意,bash中支持3种引用类型。
使用反引号(``)引起来的内容将被当做命令执行,并将执行结果返回。
如,欲查看vim命令的课执行文件的类型:
[root@localhost ~]# which vim
/usr/bin/vim
[root@localhost ~]# file `which vim`
/usr/bin/vim: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked(uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x530e3b1a3084847f35bfddc8527f432c028b7ca0, stripped
另外,使用 $(COMMAND) 也可实现相同的效果。
使用单引号(’’)可进行强引用,即引号中的内容将会按字符返回,不会被解析为其他意义(转义字符除外),所见即所得,如:
[root@localhost ~]# var1=1
[root@localhost ~]# echo $var1
1
[root@localhost ~]# echo '$var1'
$var1
使用双引号("")为若引用,引号中的内容将会被解析为变量,如:
[root@localhost ~]# var1=1
[root@localhost ~]# echo "$var1"
1
[root@localhost ~]# echo $var1
1
[root@localhost ~]# echo '$var1'
$var1
如上所示,我们一般可以省略双引号。
变量(Variable) 相信大家并不陌生,其实质上就是一段命名的内存空间。而在bash中,同样支持变量的概念。
变量类型 | 说明 |
---|---|
环境变量 | 作用域为当前shell进程及其子进程 |
本地变量 | 作用域为整个bash进程 |
局部变量 | 作用域为当前代码段(通常指函数) |
位置变量 | $1,$2,…用于让脚本在脚本代码中调用通过命令行传递给它的参数 |
特殊变量 | 保存某些特殊数据5 |
bash中变量的命名规则同其他语言类似,变量名只能包含数字、字母和下划线,而且不能以数字开头,另外,变量赋值时不能使用$。
bash为弱类型,故在声明变量时不必指定变量类型(但这不代表这些变量没有类型),可直接使用如下形式声明变量:
[set] VARNAME=VALUE
set可省略
使用不带参数的set命令可查看系统已定义的所有变量
readonly VARNAME
或
declare -r VARNAME
在声明时指定readonly,或使用declare -r,可声明只读变量(常量),由于其在声明后不可更改内容,需要在声明时进行初始化。
export VARNAME=VALUE
或
VARNAME=VALUE; export VARNAME
或
declare -x VARNAME
环境变量对当前shell及其子shell都有效
local VARNAME=VALUE
仅对局部代码生效
Linux中一切皆文件,打开的文件都有一个FD(File Description)。即文件描述符,这里特别说明一下特殊的I/O文件:
默认设备
而I/O重定向就是改变数据输入来源或输出目标的操作。
> 覆盖输出
>> 追加输出
2> 重定向错误输出(覆盖输出)
2>> 重定向错误输出(追加方式)
&> 覆盖重定向(标准输出与错误输出)
&>> 追加重定向(标准输出与错误输出)
如
[root@localhost ~]# echo 'hello world' > hello.out
[root@localhost ~]# cat hello.out
hello world
[root@localhost ~]# echo 'how are you' > hello.out
[root@localhost ~]# cat hello.out
how are you
[root@localhost ~]# echo 'new line' >> hello.out
[root@localhost ~]# cat hello.out
how are you
new line
[root@localhost ~]# ls /err 2> hello.out
[root@localhost ~]# cat hello.out
ls: cannot access /err: No such file or directory
[root@localhost ~]# lss /tmp 2>> hello.out
[root@localhost ~]# cat hello.out
ls: cannot access /err: No such file or directory
-bash: lss: command not found
[root@localhost ~]# ls / &>> hello.out
[root@localhost ~]# cat hello.out
ls: cannot access /err: No such file or directory
-bash: lss: command not found
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
管道(pipe)的作用为连接程序,实现将前一个命令的输出直接定向后一个程序当作输入数据流,即前一个命令的输出作为后一个命令的输入。用法格式为
COMMAND1 | COMMAND2 | COMMAND3 | ...
如:
[root@localhost ~]# echo 'hello world' | tr 'a-z' 'A-Z'
HELLO WORLD
tr为translate的前2个字母,可用于转换或删除字符
tr [OPTION]... SET1 [SET2]
将SET1中的字符替换为SET2的字符
[OPTION]
-d delete characters in SET1, do not translate
该命令在执行时一般使用重定向,如:
tr 'ab' 'AB' < /etc/passwd # 将/etc/passwd文件中的a或b转换成A或B
tr 'a-z' 'A-Z ' < /etc/passwd # 将/etc/passwd文件中的小写字母转换成大写
如图,tee命令可将数据流分为“两份”,一份发送到标准输出,另一份可通过重定向输出到文件。
/dev/null是使用软件模拟的特殊的设备文件
该设备被称为bit bucket,它就像一个垃圾桶,丢进去的数据都会消失。那这个设备有什么用呢?
我们知道程序的执行结果又两种,一种是正常的返回结果,另一种是程序的执行状态结果,用于标识程序是否正常执行。例如我们想知道用户“user1”是否存在,可以使用id命令6,而我们并不关心其本身信息,只是通过id命令的执行状态返回值判断其是否存在:
[root@localhost ~]# id user1 &> /dev/null
[root@localhost ~]# echo $?
1
[root@localhost ~]# useradd user1
[root@localhost ~]# id user1 &> /dev/null
[root@localhost ~]# echo $?
0
数据是以文件的形式存储在磁盘上,除了文件的数据(Data)本身,在存储时还会保存一些其他信息,即元数据(Metadata)7,时间戳信息就是其中之一。
Linux中的时间戳有三个,即
这里说明一下mtime与ctime的区别,前面提到,文件在存储时,有Data与Metadata,他们存储在不同的区域
需要注意的是,文件的mtime改变后,ctime一定会改变,因为mtime存储在Metadata中
stat意为状态,可查看文件或文件系统的状态,如:
[root@ ~]# cp /etc/fstab ./
[root@ ~]# stat fstab
File: ‘fstab’
Size: 541 Blocks: 8 IO Block: 4096 regular file
Device: fd00h/64768d Inode: 206917765 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: unconfined_u:object_r:admin_home_t:s0
Access: 2018-12-30 11:15:58.721775819 +0800
Modify: 2018-12-30 11:15:58.721775819 +0800
Change: 2018-12-30 11:15:58.721775819 +0800
Birth: -
可以看到文件的相关元数据信息,其中的Access、Modify、Change即为其时间戳信息。
touch意为触摸,用于改变文件的时间戳信息,用法如下:
touch [OPTION]... FILE...
[OPTION]
-a change only the access time 只改变访问时间
-c do not create any files 如果文件不存在也不创建
-m change only the modification time 只改变修改时间
-t STAMP
use [[CC]YY]MMDDhhmm[.ss] instead of current time
没有只修改改变时间的选项,因为对文件做的任何修改(包括时间戳)都会改变文件的属性(改变时间)
若FILE不存在,touch命令会自动创建该文件,故可使用该命令来创建文件,使用-c指定若文件不存在也不创建。
Globbing,通配,即通用匹配之意,是指用一些特殊的字符,使其不标识其本来的字面意义,而标识某一类字符集合,以此为 模式(Pattern) 进行字符匹配。
通配符 | 描述 |
---|---|
* | 任意长度的任意字符 |
? | 任意单个字符 |
[] | 匹配指定字符范围内的任意单个字符 |
[^] | 指定范围以外的任意单个字符 |
关于范围,可使用如下方式表示,如
范围 | 描述 |
---|---|
[abc] | 从abc中匹配,注意:此通配不区分大小写 |
[a-m] | 从a-m范围内匹配,注意:此通配不区分大小写 |
[0-9] | 数字 |
[a-zA-Z] | 字母 |
[[:space:]] | 空白字符 |
[[:punct:]] | 标点符号 |
[[:lower:]] | 小写字符 |
[[:upper:]] | 大写字母 |
[[:alpha:]] | 大小写字母 |
[[:digit:]] | 数字 |
[[:alnum:]] | 数字和大小写字母 |
字母开头,字母结尾,中间有空白字符:
[[:alpha:]]*[[:space:]]*[[:alpha:]]
显示/var目录下所有以l开头,以一个小写字母结尾,且中间出现至少一位数字的文件或目录;
# ls -d /var/l*[0-9]*[[:lower:]]
显示/etc目录下,以任意一位数字开头,且以非数字结尾的文件或目录;
# ls -d /etc/[0-9]*[^0-9]
显示/var目录下所有以l开头,以一个小写字母结尾,且中间出现一位任意字符的文件或目录;
# ls -d /vat/l?[[:lower:]]
显示/etc目录下,以任意一位数字开头,且以非数字结尾的文件或目录;
# ls -d /etc/[0-9]*[^0-9]
显示/etc目录下,以非字母开头,后面跟一个字母及其它任意长度任意字符的文件或目录;
# ls -d /etc/[^[:alpha:]][a-z]*
复制/etc目录下,所有以m开头,以非数字结尾的文件或目录至/tmp/brahming目录;
# cp -r /etc/m*[^0-9] /tmp/brahming
复制/usr/share/man目录下,所有以man开头,后跟一个数字结尾的文件或目录至/tmp/man/目录下;
# cp -r /usr/share/man/man*[0-9] /tmp/man
复制/etc目录下,所有以.conf结尾,且以m,n,r,p开头的文件或目录至/tmp/conf.d/目录下;
# cp -r /etc/[mnrp]*.com /tmp/conf.d
现代的计算机都是多任务(Multi-Tasks)与多用户(Multi-Users) 的,早期的计算机由于各种原因,并不是每个人独立拥有一台计算机,而计算机用户的概念就可以用户标识每一位使用者。如今,这一概念已经普遍使用。
对于Linux系统而言,用户是系统进行资源分派的单位,其主要关注:
UID(User ID),即用户ID,UID是系统用于标识用户的字符,用户输入的登录名(即用户名)也将会映射为UID进而有系统处理。
UID的范围规定在 /etc/login.defs文件中
UID与用户名的映射关系保存于文件 /etc/passwd中
组(Group) 是用户的容器,若几个用户属于一个组,就有了这个组拥有的权限,可以说组是一个权限设定的容器。
和UID相同,GID(Grou ID) 即组ID,用于标识一个组。
useradd以为用户添加,用法如下:
useradd [options] USERNAME
[options]
-u UID 指定UID,其他用户尚未使用的
-g GID 指定GID(基本组),组要事先存在,可为组名,也可为GID
-G GID,... 指定GID(附加组),组要事先存在,可为组名,也可为GID,多个组之间使用逗号分隔
-c "COMMENT" 指定注释信息
-d, --home /PATH/TO/SOMEDIRECTORY
指定家目录
通过复制/etc/skel目录并重命名的方式实现
若指定的目录事先存在,则不会为用户复制环境配置文件
-s SHELL 指定shell
/etc/shells指定了当前系统可用的安全shell
默认为/etc/default/useradd 中的 SHELL 变量中指定的shell
-m -k 强制为用户创建家目录,并且当-k选项启用时,将/etc/skel/下的文件复制到当前用户的家目录
-M 不为用户创建家目录,即使/etc/login.defs中允许创建
-r 添加一个系统用户
不会用用户创建家目录
默认shell为/sbin/nologin
-D 显示创建用户的默认配置
-D[options] 修改选项的值
修改的结果保存于/etc/default/useradd文件中
-f 指定账户非活动期限,指定-1则永不禁用
关于配置文件,后文将介绍
另外,也可使用adduser命令,该命令为useradd命令的符号链接
[root@ ~]# file `which adduser`
/usr/sbin/adduser: symbolic link to `useradd'
userdel即User Delete,删除用户,该命令用法较为简单:
userdel [options] USERNAME
[options]
-r 同时删除家目录,默认不会删除
usermod为User Modify,可用于更改用户的属性,用法为:
usermod [options] USERNAME
[options]
-u 修改UID
-g 修改基本组
-G 修改附加组,如果用户此前已经有附加组,修改后会覆盖此前的附加组
-a -G 追加(append)附加组
-c 修改注释信息
-d 修改家目录,默认不会迁移用户的家目录,也不会创建指定目录
-d -m 修改家目录并且将原来目录中的文件移动至修改后的目录
-s 修改用户shell
-l 修改用户登录名
-L 锁定账号,锁定后无法登录
-U 解锁账号
passwd命令也可以锁定与解锁账户
-e YYYY-MM-DD
指明用户账号过期日期
-f INACTIVE
设定账户非活动期限
passwd即Password,密码之意,可用于更新用户的认证信息(如密码),用法如下:
passwd [OPTION] [USERNAME]
[OPTION]
--stdin 从标准输入读取用户密码
例:
echo "redhat" | passwd --stdin user3
-l 锁定账号
-u 解锁账号
账户锁定后,/etc/shadow文件该账户对应条目密码字段前会多一个感叹号(!),可手动加上,以锁定用户
-e DATE 过期期限
-n mindays 指定最短使用期限
-x maxdays 最大使用期限
-w warndays 提前多少天开始警告
-i inactivedays 非活动期限
-d 删除用户密码
红帽系统会禁止空密码用户登录
前文有提到,可使用id命令查看用户信息:
id [OPTION]... [USER]
[OPTION]
-u 仅显示有效的UID
-g 仅显示基本组ID
-G 所有组的GID(包括基本组可附加组)
-r 显示真实ID
-n 以上命令统与-n一起使用,则显示名称,而不是ID号
不带参数的id命令可用于查看自己的信息,如:
[root@ ~]# id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
su即switch user,可用于切换用户,在介绍命令用法之前,先介绍一下Shell类型。
站在用户的角度,Shell分为登录式Shell与非登录式Shell
su的选项:
su [options...] [-] [user [args...]]
[options]
-l:“su -l UserName”相当于“su - UserName”
-c 'COMMAND':仅以指定用户的身份运行此处指定的命令
chage以为change age,可修改用户的账号过期信息
chage [options] USER
[options]
-d 最近一次修改时间(YYYY-MM-DD)
-E 账号的过期(禁用)时间(YYYY-MM-DD)
-I 非活动时间,即用户锁定后允许用户修改密码的时间
-m 密码最短使用期限
-M 密码最长使用期限
-W 警告时长
-l 显示用户密码过期信息
该命令可修改用户的默认shell
查看自己的用户名
验证密码文件的完整性
验证组文件的完整性
修改用户的注释信息
groupadd可用于创建一个新组,用法为:
groupadd [options] group
[options]
-g GID 指定GID,如不指定,则为系统中最高GID+1
-r 添加为系统组
groupdel用于删除用户组
groupmod可修改组信息,用法有groupadd相似:
groupmod [options] GROUP
[options]
-g GID 修改GID
-n GRPNAME 修改组名
gpasswd拥有给组添加密码,用法:
gpasswd [OPTIONS] GROUPNAME
[OPTIONS]
-a USER 将USER添加至指定组中
-d USER 删除用户USER的以当前组为组名的附加组
-A user1,user2,... 设置有管理权限的用户列表
-M Set the list of group members.
newgrp即new group,可临时切换指定组为用户的基本组
nwegrp [-] [group]
-:会模拟用户重新登录以实现重新初始化其工作环境
该文件是用户信息数据库,每一行定义一个用户。以root为例,内容为:
[root@ ~]# head -1 /etc/passwd
root:x:0:0:root:/root:/bin/bash
该文件的每一行有7个字段,用于共同指定一个用户的相关信息,中间使用半角冒号(:)分隔,依次为用户名、密码、用户ID、用户私有组ID、用户注释、家目录、用户默认shell程序,即:
account:password:UID:GID:GECOS:directory:shell
字段 | 说明 |
---|---|
account | 登陆名 |
password | 可以是加密的密码,也可以是占位符(man 8 pwconv查看) |
UID | the numerical user ID |
GID | 基本组(私有组)ID |
GECOS | 可选的,用户的注释(comment)信息 |
directory | the user’s $HOME directory |
shell | 用户的默认shell(/etc/shells指定了当前系统可用的安全shell) |
可使用man 5 passwd查看文件格式信息
该文件为真正的密码文件,主要保存认证口令,依然是每一行用于记录一个用户的信息,以root为例,内容为:
[root@ ~]# head -1 /etc/shadow
root:$6$ZoCI8lk/jgp94iAd$DoJAlzqhNm4rkITOB4Dk/C9xZIw2nyv6AwT6YFosfidI6g9bpEx1YrrRncQEpR9a97Z/m0WBuNer5ukS7znHc0:17884:0:99999:7:::
另外该文件还记录了用户密码的使用时间,如用户密码的最长使用天数、用户当前密码已经使用的天数、账户的失效时间、密码的非活动时间等,文件格式为:
login name:encrypted password:date of last password change:minimum password age:maximum password age:password warning period:password inactivity period:account expiration date:reserved field
各部分说明如下
字段 | 说明 |
---|---|
login name | 登录名 |
encrypted password | 加密后的密码 |
date of last password change | 自1970.1.1至上次修改密码经过的天数 |
minimum password age | 密码最短使用天数 |
maximum password age | 密码最长使用天数 |
password warning period | 密码警告区间,即自上次修改密码至密码有效天数前的时间(天) |
password inactivity period | 密码非活动区间,及在用户密码过期之后、禁用之前的天数 |
account expiration date | 账户过期时间,自1970.1.1至账户禁用的天数 |
reserved field | 保留字段 |
加密方式的标识8
ID | Method |
---|---|
1 | MD5 |
2a | Blowfish (not in mainline glibc; added in some Linux distributions) |
5 | SHA-256 (since glibc 2.7) |
6 | SHA-512 (since glibc 2.7) |
可使用man 5 shadow查看该文件格式信息
此处简单说明单向加密
在/etc/default/useradd中定义了useradd命令的相关默认信息,以下为该文件内容:
[root@ ~]# cat /etc/default/useradd
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
useradd使用-D选项修改的内容将保存于该文件中
用户的当前shell保存在环境变量SHELL中
/etc/skel/中有一些环境配置文件
/etc/login.defs文件中有PASS_MAX_DAYS, PASS_MIN_DAYS, PASS_MIN_LEN, PASS_WARN_AGE, UID与GID的最大最小数等默认参数
File | Description9 |
---|---|
/etc/passwd | User account information. |
/etc/shadow | Secure user account information. |
/etc/group | Group account information. |
/etc/gshadow | Secure group account information. |
/etc/default/useradd | Default values for account creation. |
/etc/skel/ | Directory containing default files. |
/etc/login.defs | Shadow password suite configuration. |
该文件存储了组名与GID的映射关系,依然是使用冒号分隔,每行定义一个组,格式为:
该文件与/etc/shadow类似,保存加密后的组密码,使用冒号分隔,每行定义一个组:
group name:encrypted password:administrators:members
进程是用户操作计算机的代理,进程运行时,是以发起者的身份运行,进程能范围内那些文件,取决于进程本身的权限以及发起者的权限
读(Read),以r标识
写(Write),以w标识
执行(eXecute),以x标识
在使用ls -l查看文件信息时,可以看到文件权限有三组10,分别对应属主、数组、其他用户。每一组有三位,用于标识是否具有该权限,即每一位的变化有两种,如此每一位可以使用一位二进制数字表示,每一组可以使用一位8进制数字表示,对应关系如下
权限位 | 二进制 | 八进制 | 意义 |
---|---|---|---|
--- | 000 | 0 | 无权限 |
--x | 001 | 1 | 执行 |
-w- | 010 | 2 | 写 |
-wr | 011 | 3 | 写,执行 |
r-- | 100 | 4 | 读 |
r-x | 101 | 5 | 读,执行 |
rw- | 110 | 6 | 读,写 |
rwx | 111 | 7 | 读,写,执行 |
该位上有对应权限则为1,没有则为0,遂用三组八进制数字表示,分别表示属主、属组、其他用户的权限,如:
字符表示 | 二进制表示 | 八进制表示 |
---|---|---|
rw-r----- | 110100000 | 640 |
rwxr-xr-x | 111101101 | 755 |
rw-rw---- | 110110000 | 660 |
rwxrwxr-x | 111111101 | 775 |
我们知道,一个文件(或目录)若所有用户都有权限进行所有操作,则为777,若所有用户都没有权限进行任何操作,则为000,然而在创建文件的时候,权限为644,这是为什么呢?
在我们进行创建的时候,系统将待创建对象的所有权限位置为1,而由于默认给一个文件执行权限是非常危险的,故在创建目录与文件时,默认给定的最大权限不同:
但是如此的默认权限给定方式显然也是不合适的,故有了权限掩码(Mode Mask) 的概念。掩码,也叫遮罩码,即为遮挡之意。
由于管理员与普通用户的权限不同,其默认的权限掩码也不相同,可使用umask命令查看
umask是一个内部命令,用于显示或设置用户的权限掩码
由于设置权限掩码的命令名为umask,故我们也将权限掩码称为umask
不带参数的umask命令可以查看当前用户的umask
[root@localhost ~]# umask
0022
[root@localhost ~]# useradd user1
[root@localhost ~]# su user1
[user1@localhost ~]$ umask
0002
[user1@localhost ~]$ exit
logout
[root@localhost ~]# groupadd group1
[root@localhost ~]# useradd -g group1 user2
[root@localhost ~]# su user2
[user2@localhost root]$ umask
0022
返回4位数字,最高位为特殊权限的掩码,这里暂且不论11
由直接结果可知,管理员的umask默认为022,普通用户的默认umask:
有如下例子:
[user1@localhost ~]$ clear
[user1@localhost ~]$ id
uid=1000(user1) gid=1000(user1) groups=1000(user1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[user1@localhost ~]$ umask 023
[user1@localhost ~]$ touch test.file
[user1@localhost ~]$ ll test.file
-rw-r--r--. 1 user1 user1 0 Dec 30 20:27 test.file
chown意为change owner,可用于修改文件的属主或属组,用法如下:
# chown USERNAME file,... 修改属主
# chown :GRPNAME file,... 修改属组
# chown .GRPNAME file,... 修改属组
# chown USERNAME:GRPNAME file,... 修改属主属组
# chown USERNAME.GRPNAME file,... 修改属主属组
参数
-R 递归修改,修改目录及其内部文件的属主
--reference=/PATH/TO/SOMEFILE file,...
reference,参考,将file的属主属组设置为与/PATH/TO/SOMEFILE相同
只有管理员才可以执行此命令
chgrp为change group之意,用于修改文件的属组,用法为:
chgrp [OPTION]... GROUP FILE...
[OPTION]
--reference=RFILE
参考目标文件的属组设定
chmod意为change mode,用于修改文件的权限信息,用法为:
chmod [OPTION]... MODE[,MODE]... FILE...
操作三类用户的权限,使用8进制形式
例: chmod 775 /tmp/abc
(75==075, 5==005)
chmod [OPTION]... OCTAL-MODE FILE...
操作指定类别用户的权限,使用u,g,o,a来赋权,可以基于=或+/-来进行
[OPTION]...
--reference=RFILE FILE...
参照其他文件的权限为当前文件赋权
-R: 递归修改,修改目录及其内部文件的权限(目录下的符号链接除外)
chmod [USER_TYPE]+|-|=MODE file,...
修改某类用户或某些用户权限
[USER_TYPE]
u: owner 属主
g: group 属组
o: other 其他用户
a: all 所有用户
=:操作指定类别用户的权限
+/-:操作指定类别用户的单个权限
例:
chmod o=rx /tmp/abc 修改其他用户的权限为r-x
chmod gu=rx /tmp/abc 修改属主属组的权限为r-x
chmodu-x /tmp/abc 去掉属主的执行权限
chmod u+x,g-x /tmp/abc
chmod a+x /tmp/abc 修改三类用的权限(此处为加执行权限)
a可以省略,写成chmod +x /tmp/abc
目前的最新版为FHS3.0,详见 https://refspecs.linuxfoundation.org/fhs.shtml ↩︎
引用自 https://refspecs.linuxfoundation.org/FHS_2.3/fhs-2.3.html#THEVARHIERARCHY ↩︎
表格内容引用自 https://www.ibm.com/developerworks/cn/linux/l-cn-sysfs/ ↩︎
后文会详细介绍命令别名 ↩︎
关于特殊变量后续会详细介绍 ↩︎
关于用户管理类命令后文将介绍 ↩︎
后续将详细介绍 ↩︎
可使用man 3 crypt查看 ↩︎
表格摘自USERADD(8)-FILES ↩︎
详见 https://blog.csdn.net/xiyangyang410/article/details/85043737#ls_387 ↩︎
后续将介绍 ↩︎