跳转至

linux运维能力

004_linux

1.配置镜像

一、配置阿里云镜像 参考:Ubuntu如何配置软件镜像源?_ubuntu源配置-CSDN博客

Bash
1
2
3
4
5
6
7
8
# 打开sources.list
sudo vi /etc/apt/sources.list

# 阿里云镜像
deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

二、上述阿里云镜像有点问题,需要改成-ports 参考:【换源踩坑】arrch62版本ubuntu 换源失败-CSDN博客

Bash
1
2
3
4
deb http://mirrors.aliyun.com/ubuntu-ports/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu-ports/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu-ports/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu-ports/ focal-backports main restricted universe multiverse

三、配置swap区 ubuntu 为swap添加空间(交换空间)_51CTO博客_ubuntu增加swap交换空间

2. shell基础

shell也是一种程序,有不同的实现版本,例如bashdash等。

Text Only
1
2
3
4
5
6
7
8
9
ubuntu@VM-8-7-ubuntu:/bin$ ll /bin | grep "sh"
-rwxr-xr-x  1 root root 1113504 Apr 18  2022 bash*
-rwxr-xr-x  1 root root  121432 Jan 25  2018 dash*
-rwxr-xr-x  1 root root    7208 Dec 31  2012 mlnx_conf_mgr.sh*
-rwxr-xr-x  1 root root   14268 Dec 31  2012 mlnx_interface_mgr.sh*
lrwxrwxrwx  1 root root       4 Apr 18  2022 rbash -> bash*
lrwxrwxrwx  1 root root       4 Aug  8  2018 sh -> dash*
lrwxrwxrwx  1 root root       4 Aug  8  2018 sh.distrib -> dash*
lrwxrwxrwx  1 root root       7 Nov 25  2021 static-sh -> busybox*

可以看出这台机器上有bashdash两种shell实现,并且平常经常用的sh命令实则是软链接到dash

2.1. 使用哪种shell?

至于系统启动时采用哪种shell程序取决于在/etc/paswd文件中的个人配置,例如:

Text Only
1
2
3
4
5
6
7
8
9
# 查看用户配置的shell程序
ubuntu@VM-8-7-ubuntu:~$ cat -n /etc/passwd | grep bash
     1  root:x:0:0:root:/root:/bin/bash
    30  ubuntu:x:500:500:ubuntu,,,:/home/ubuntu:/bin/bash
    33  lighthouse:x:1000:1000::/home/lighthouse:/bin/bash

# 查看当前使用的shell程序
ubuntu@VM-8-7-ubuntu:/bin$ echo $SHELL
/bin/bash

可以看出,三个用户rootubuntulighthouse都是使用/bin/bash

2.2. shell本质是什么?

查看readelf -h /bin/bash可知bash是个Shared object file

Text Only
ubuntu@VM-8-7-ubuntu:~$ readelf -h /bin/bash
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              DYN (Shared object file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x31530
  Start of program headers:          64 (bytes into file)
  Start of section headers:          1111712 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         28
  Section header string table index: 27
ubuntu@VM-8-7-ubuntu:~$ file /bin/bash
/bin/bash: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=6386b644ab2d987986aeb40325a787a035a4f0d8, stripped

2.3. shell可以嵌套

Text Only
# 查看进程关系:bash进程(27808)是ps进程(30281)的父进程
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   27808 27807  0 07:48 pts/0    00:00:00 -bash
ubuntu   30281 27808  0 07:58 pts/0    00:00:00  \\_ ps -f --forest

# bash中运行dash
ubuntu@VM-8-7-ubuntu:~$ /bin/dash
# dash中运行bash
$ /bin/bash

# 查看进程关系:3层父子进程关系
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   27808 27807  0 07:48 pts/0    00:00:00 -bash
ubuntu   30315 27808  0 07:58 pts/0    00:00:00  \\_ /bin/dash
ubuntu   30361 30315  0 07:59 pts/0    00:00:00      \\_ /bin/bash
ubuntu   30382 30361  0 07:59 pts/0    00:00:00          \\_ ps -f --forest

image-20230716154832728

在生成子进程shell时,只有部分父进程的环境被复制到子shell环境中。

exit命令可以退出当前shell,当最外层的shell执行exit后,就退出cli了。

shell的内建命令**

外部命令,有时候也被称为文件系统命令,是存在于bash shell之外的程序。它们并不是shell程序的一部分。外部命令程序通常位于/bin/usr/bin/sbin/usr/sbin中。

当外部命令执行时,会fork创建一个子进程执行具体任务。例如,ps命令就是典型的外部命令,虽然看似简单,但是确实以子进程的身份执行命令:

Text Only
1
2
3
4
5
# 查看进程关系:bash进程(27808)是ps进程(30281)的父进程
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   27808 27807  0 07:48 pts/0    00:00:00 -bash
ubuntu   30281 27808  0 07:58 pts/0    00:00:00  \\_ ps -f --forest

内建命令与外部命令的区别在于前者不需要使用子进程来执行,它们已经和shell编译成了一体,作为shell工具的组成部分存在,不需要借助外部程序文件来运行。

Text Only
# ps是外部命令
ubuntu@VM-8-7-ubuntu:~$ which ps
/bin/ps
ubuntu@VM-8-7-ubuntu:~$ type ps
ps is hashed (/bin/ps)

# cd是内建命令
ubuntu@VM-8-7-ubuntu:~$ which cd
ubuntu@VM-8-7-ubuntu:~$ type cd
cd is a shell builtin

有些命令既有内建实现也有外部实现,type -a可以查看命令的这两种实现,而which命令只显示外部命令文件

Text Only
1
2
3
4
5
6
7
8
# 可见echo命令有内外两种实现
ubuntu@VM-8-7-ubuntu:~$ type -a echo
echo is a shell builtin
echo is /bin/echo

# which命令只显示外部实现
ubuntu@VM-8-7-ubuntu:~$ which -a echo
/bin/echo

2.4. history历史命令

history是bash shell的内建命令,即shell工具会记录历史命令。

Text Only
# history是bash shell的内建命令
ubuntu@VM-8-7-ubuntu:~$ type -a history
history is a shell builtin

# dash shell中就没有history命令
ubuntu@VM-8-7-ubuntu:~$ dash
$ type history
history: not found
$ history
dash: 2: history: not found

可通过配置bash配置文件(例如~/.bashrc)修改HISTSIZE配置保存最近的命令数量:

Text Only
# 默认会保存1000条
ubuntu@VM-8-7-ubuntu:~$ cat .bashrc | grep HISTSIZE
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
#HISTSIZE=1000

# 使用vi修改HISTSIZE后,通过source ~/.bashrc生效修改
ubuntu@VM-8-7-ubuntu:~$ cat .bashrc | grep HISTSIZE
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=5
ubuntu@VM-8-7-ubuntu:~$ source ~/.bashrc
ubuntu@VM-8-7-ubuntu:~$ history
  538  2023-06-04 10:24:25 hisory
  539  2023-06-04 10:24:29 clear
  540  2023-06-04 10:24:31 cat .bashrc | grep HISTSIZE
  541  2023-06-04 10:24:33 source ~/.bashrc
  542  2023-06-04 10:24:36 history

使用!!可以换回并执行历史列表中最近的命令:

Text Only
1
2
3
4
5
6
# 当输入!!时,bash首先会显示出从shell的历史记录中唤回的命令。然后执行该命令。
ubuntu@VM-8-7-ubuntu:~$ echo "hello,world"
hello,world
ubuntu@VM-8-7-ubuntu:~$ !!
echo "hello,world"
hello,world

命令历史记录保存在~/.bash_history文件中

Text Only
ubuntu@VM-8-7-ubuntu:~$ echo "hello1"
hello1
ubuntu@VM-8-7-ubuntu:~$ echo "hello2"
hello2
ubuntu@VM-8-7-ubuntu:~$ echo "hello3"
hello3
ubuntu@VM-8-7-ubuntu:~$ echo "hello4"
hello4
ubuntu@VM-8-7-ubuntu:~$ tail .bash_history
#1685845805
clear
#1685845811
echo "hello1"
#1685845813
echo "hello2"
#1685845815
echo "hello3"
#1685845817
echo "hello4"

2.5. alias命令别名

alias命令是另一个shell的内建命令。命令别名允许你为常用的命令(及其参数)创建另一个名称,从而将输入量减少到最低。

Text Only
# alias是bash shell的内建命令
ubuntu@VM-8-7-ubuntu:~$ type -a alias
alias is a shell builtin

# alias -p查看现有命令别名
ubuntu@VM-8-7-ubuntu:~$ alias -p
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'

# 平常使用的ll命令并非是真实存在的可执行程序或文件,而只是对ls命令及其参数进行封装的别名
ubuntu@VM-8-7-ubuntu:~$ which -a ll
ubuntu@VM-8-7-ubuntu:~$ type ll
ll is aliased to `ls -alF'

如下演示如何自定义命令别名:

Text Only
# 格式为alias 目标别名="源命令和参数组合"
ubuntu@VM-8-7-ubuntu:~$ alias say_hello='echo "hello"'

# 查看后可见say_hello已经命名成功
ubuntu@VM-8-7-ubuntu:~$ alias -p
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -alF'
alias ls='ls --color=auto'
alias say_hello='echo "hello"'

# 执行命令观察效果符合预期
ubuntu@VM-8-7-ubuntu:~$ say_hello
hello

定义命令别名后,也可以在shell脚本中使用。需要注意的是,因为命令别名属于内建命令,一个别名仅在它所定义的shell进程中才有效。

2.6. 环境变量

bash shell中环境变量分为两类:

  • 全局环境变量:对于shell会话和所有生成的子shell都是可见的
  • 局部环境变量:只对创建它们的shell可见
  • 用户定义环境变量

2.6.1. 全局环境变量

查看所有全局变量,可用env命令或printenv命令;查看个别全局变量的值则需要用printenv命令或echo命令:

Text Only
# printenv和env都是/usr/bin下的外部命令
ubuntu@VM-8-7-ubuntu:~$ type -a printenv
printenv is /usr/bin/printenv
ubuntu@VM-8-7-ubuntu:~$ type -a env
env is /usr/bin/env

# prntenv和env都可以显示所有全局变量
ubuntu@VM-8-7-ubuntu:~$ printenv | tail
SHELL=/bin/bash
SHLVL=1
PROMPT_COMMAND=history -a; history -a; history -a;
LOGNAME=ubuntu
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/500/bus
XDG_RUNTIME_DIR=/run/user/500
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
HISTSIZE=1000
LESSOPEN=| /usr/bin/lesspipe %s
_=/usr/bin/printenv
ubuntu@VM-8-7-ubuntu:~$ env | tail
SHELL=/bin/bash
SHLVL=1
PROMPT_COMMAND=history -a; history -a; history -a;
LOGNAME=ubuntu
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/500/bus
XDG_RUNTIME_DIR=/run/user/500
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
HISTSIZE=1000
LESSOPEN=| /usr/bin/lesspipe %s
_=/usr/bin/env

# printenv能显示具体全局变量的内容, 但是env不能
ubuntu@VM-8-7-ubuntu:~$ printenv PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ubuntu@VM-8-7-ubuntu:~$ env PATH
env: ‘PATH’: No such file or directory

# 全局环境变量前加上$符号,也可以被shell解析
ubuntu@VM-8-7-ubuntu:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
ubuntu@VM-8-7-ubuntu:~$ ll $SHELL
-rwxr-xr-x 1 root root 1113504 Apr 18  2022 /bin/bash*

2.6.2. 局部环境变量

linux中没有只显示局部环境变量的命令,set命令会显示指定进程所有的环境环境,包括全局/局部/用户定义环境变量。即所有通过printenv命令能看到的全局环境变量都出现在了set命令的输出中,但在set命令的输出中还有其他一些环境变量,即局部环境变量和用户定义变量。

set命令输出的内容过多,就不演示了。

下面演示如何设置局部环境变量:

Text Only
# 当前不存在局部环境变量env_local_val
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val

# 定义局部环境变量:env_local_val
ubuntu@VM-8-7-ubuntu:~$ env_local_val="hello, world"
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val
hello, world
# 创建一个新的bash shell进程,子进程内不存在环境变量env_local_val
ubuntu@VM-8-7-ubuntu:~$ /bin/bash
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   32190 32189  0 08:06 pts/0    00:00:00 -bash
ubuntu   15437 32190  0 11:21 pts/0    00:00:00  \\_ /bin/bash
ubuntu   15484 15437  0 11:21 pts/0    00:00:00      \\_ ps -f --forest
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val

# 子进程中定义局部环境变量:env_inner_local_val
ubuntu@VM-8-7-ubuntu:~$ env_inner_local_val="this is another shell process"
ubuntu@VM-8-7-ubuntu:~$ echo $env_innner_local_val

ubuntu@VM-8-7-ubuntu:~$ echo $env_inner_local_val
this is another shell process
ubuntu@VM-8-7-ubuntu:~$ exit
exit
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   32190 32189  0 08:06 pts/0    00:00:00 -bash
ubuntu   15888 32190  0 11:23 pts/0    00:00:00  \\_ ps -f --forest
# 父进程中不存在子进程中定义的环境变量:env_inner_local_val
ubuntu@VM-8-7-ubuntu:~$ echo $env_inner_local_val

ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val
hello, world

# 退出子进程后,再次进程子进程,之前定义的局部环境变量已经失效了
ubuntu@VM-8-7-ubuntu:~$ /bin/bash
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   32190 32189  0 08:06 pts/0    00:00:00 -bash
ubuntu   16016 32190  0 11:24 pts/0    00:00:00  \\_ /bin/bash
ubuntu   16046 16016  0 11:24 pts/0    00:00:00      \\_ ps -f --forest
ubuntu@VM-8-7-ubuntu:~$ echo $env_inner_local_val

ubuntu@VM-8-7-ubuntu:~$

即局部环境变量是属于所定义的进程实例自身,对子进程不可见,当进程销毁后就会失效。

创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局变量中:

Text Only
# printenv输出的全局变量中找不到env_local_val
ubuntu@VM-8-7-ubuntu:~$ printenv | grep env_local_val
# 通过export命令把env_local_val添加到全局变量中
ubuntu@VM-8-7-ubuntu:~$ export env_local_val
# printenv输出的全局变量中可以找到env_local_val
ubuntu@VM-8-7-ubuntu:~$ printenv | grep env_local_val
env_local_val=hello, world
# 新建bash shell子进程
ubuntu@VM-8-7-ubuntu:~$ /bin/bash
ubuntu@VM-8-7-ubuntu:~$ ps -f --forest
UID        PID  PPID  C STIME TTY          TIME CMD
ubuntu   32190 32189  0 08:06 pts/0    00:00:00 -bash
ubuntu   30015 32190  0 12:20 pts/0    00:00:00  \\_ /bin/bash
ubuntu   30070 30015  0 12:21 pts/0    00:00:00      \\_ ps -f --forest
# 子进程shell可以看到env_local_val
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val
hello, world
# 子进程中修改全局变量
ubuntu@VM-8-7-ubuntu:~$ env_local_val="inner shell hello,world"
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val
inner shell hello,world
ubuntu@VM-8-7-ubuntu:~$ exit
exit
# 子进程的修改不会对父进程构成影响
ubuntu@VM-8-7-ubuntu:~$ printenv | grep env_local_val
env_local_val=hello, world

2.6.3. 删除环境变量

通过unset命令删除环境变量:

Text Only
1
2
3
4
5
6
7
8
ubuntu@VM-8-7-ubuntu:~$ printenv | grep env_local_val
env_local_val=hello, world
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val
hello, world
ubuntu@VM-8-7-ubuntu:~$ unset env_local_val
ubuntu@VM-8-7-ubuntu:~$ echo $env_local_val

ubuntu@VM-8-7-ubuntu:~$ printenv | grep env_local_val

2.6.4. 设置PATH环境变量

PATH环境变量定义了用于进行命令和程序查找的目录:

Text Only
# tree命令以树状结构显示目录
ubuntu@VM-8-7-ubuntu:~/test$ which tree
/usr/bin/tree
ubuntu@VM-8-7-ubuntu:~/test$ tree .
.
├── version1
│   └── my_test
└── version2
    └── my_test

2 directories, 2 files
# version1和version2两个目录下都有同名可执行程序my_test
ubuntu@VM-8-7-ubuntu:~/test$ ./version1/my_test
running version_1
ubuntu@VM-8-7-ubuntu:~/test$ ./version2/my_test
running version_2
# 将version1和version2目录加入环境变量
ubuntu@VM-8-7-ubuntu:~/test$ PATH=$PATH:~/test/version1:~/test/version2
ubuntu@VM-8-7-ubuntu:~/test$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/home/ubuntu/test/version1:/home/ubuntu/test/version2
# 执行my_test,发现执行的是version1/my_test
ubuntu@VM-8-7-ubuntu:~/test$ my_test
running version_1
ubuntu@VM-8-7-ubuntu:~/test$ which my_test
/home/ubuntu/test/version1/my_test

执行my_test,从运行结果上看,PATH中的的靠前目录中的同名可执行文件优先级更高。

2.7. 启动shell的三种场景

启动bash shell有3种方式:

  • 登录时作为默认登录shell,例如:ssh远程登录linux系统
  • 作为非登录shell的交互式shell,例如:在shell中嵌套启动shell,或在桌面上启动终端
  • 作为运行脚本的非交互式shell,例如:通过/bin/bash解释运行.sh脚本

2.7.1. 登录shell

登录shell会从5个不同的启动文件中读取命令:

  • 系统级:
  • /etc/profile:系统默认的bash shell主启动文件,每个用户登录时都会执行
  • 用户级:
  • 三选一:shell会按如下次序,运行第一个找到的文件,余下的则会被忽略:
    • $HOME/.bash_profile
    • $HOME/.bash_login
    • $HOME/.profile
  • $HOME/.bashrc:通常是通过上述三个文件中调用运行

用户自定义的永久性全局变量建议放在$HOME/.bashrc启动文件中。

如下ubuntu系统实测:

Text Only
# 用户级三选一中,只有.profile
ubuntu@VM-8-7-ubuntu:~$ ll .bash_profile .bash_login .profile
ls: cannot access '.bash_profile': No such file or directory
ls: cannot access '.bash_login': No such file or directory
-rw-r--r-- 1 ubuntu ubuntu 148 Mar 18  2021 .profile
# 查看.profile内容,其中运行了.bashrc
ubuntu@VM-8-7-ubuntu:~$ cat .profile
# ~/.profile: executed by Bourne-compatible login shells.

if [ "$BASH" ]; then
  if [ -f ~/.bashrc ]; then
    . ~/.bashrc
  fi
fi

mesg n || true

2.7.2. 交互式shell

如果bash是作为交互式shell启动的,它就不会访问/etc/profile文件,只会检查用户HOME目录中的.bashrc文件。

个人理解原因:子进程会继承父进程的环境变量,保证了子进程shell环境变量是够用的,同时这也是个保守的设计,保证子进程的环境变量范围至少不会超过父进程,才是合理的

2.7.3. 非交互式shell

bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件,shell会执行该文件里的命令,这通常包括shell脚本变量设置。

如果BASH_ENV变量没有设置,shell脚本到哪里去获得它们的环境变量呢?子shell可以继承父shell导出过的变量。举例来说,如果父shell是登录shell,在/etc/profile/etc/profile.d/*.sh$HOME/.bashrc文件中设置并导出了变量,用于执行脚本的子shell就能够继承这些变量。

理解同“交互式shell”,即通过继承父进程shell的全局环境变量。

同时也可配置BASH_ENV

3. Linux权限管理

3.1. /etc/passwd文件

Linux系统使用一个专门的文件来将用户的登录名匹配到对应的UID值。这个文件就是/etc/passwd文件:

Text Only
1
2
3
4
ubuntu@VM-8-7-ubuntu:~$ cat /etc/passwd | grep -E "ubuntu|root|lighthouse"
root:x:0:0:root:/root:/bin/bash
ubuntu:x:500:500:ubuntu,,,:/home/ubuntu:/bin/bash
lighthouse:x:1000:1000::/home/lighthouse:/bin/bash

/etc/passwd文件的字段包含了如下信息:

  • 登录用户名
  • 用户密码:密码字段都被设置成x显示,真实的密码放在/etc/shadow文件中
  • 用户账户的UID
  • 用户账户的组ID,即GID
  • 用户账户的文本描述,成为备注字段
  • 用户HOME目录的位置
  • 用户的默认shell

root用户账户是Linux系统的管理员,固定分配给它的UID是0。Linux为系统账户预留了500以下的UID值。有些服务甚至要用特定的UID才能正常工作。为普通用户创建账户时,大多数Linux系统会从500开始,例如上面ubuntu用户的UID就是500。

3.2. /etc/shadow文件

所有用户都能访问/etc/passwd文件,只有root用户才能访问/etc/shadow文件

Text Only
1
2
3
ubuntu@VM-8-7-ubuntu:~$ ll /etc/passwd /etc/shadow
-rw-r--r-- 1 root root   1765 May  2 17:21 /etc/passwd
-rw-r----- 1 root shadow 1040 May  2 17:21 /etc/shadow

3.3. 增删改用户

useradd命令用于添加新用户,可以一次性创建新用户即设置用户HOME目录结构。

useradd -D可以查看创建新用户时的默认配置值,这些配置可通过/etc/default/useradd文件进行修改:

Text Only
ubuntu@VM-8-7-ubuntu:~$ useradd -D
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/sh
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no

ubuntu@VM-8-7-ubuntu:~$ ls -al /etc/skel/
total 28
drwxr-xr-x   2 root root  4096 Oct  8  2022 .
drwxr-xr-x 113 root root 12288 May  3 17:02 ..
-rw-r--r--   1 root root   220 Apr  5  2018 .bash_logout
-rw-r--r--   1 root root  3771 Apr  5  2018 .bashrc
-rw-r--r--   1 root root   807 Apr  5  2018 .profile

默认配置值说明:

  • 新用户会被添加到GID为100的公共组
  • 新用户的HOME目录将会位于/home/loginname
  • 新用户账户密码在过期后不会被禁用
  • 新用户账户未被设置过期日期
  • 新用户账户将/bin/sh作为默认shell
  • 系统会将/etc/skel目录下的内容复制到用户的HOME目录下:useradd命令允许管理员创建一份默认的HOME目录配置,然后把它作为创建新用户HOME目录的模板。这样就能自动在每个新用户的HOME目录里放置默认的系统文件。
  • 系统不会为该用户账户在mail目录下创建一个用于接收邮件的文件

默认情况下,useradd命令不会创建HOME目录,但是-m命令行选项会使其创建HOME目录

Text Only
ubuntu@VM-8-7-ubuntu:~$ sudo useradd -m test
ubuntu@VM-8-7-ubuntu:~$ ll -al /home/test/
total 20
drwxr-xr-x 2 test test 4096 Jun  4 16:15 ./
drwxr-xr-x 5 root root 4096 Jun  4 16:15 ../
-rw-r--r-- 1 test test  220 Apr  5  2018 .bash_logout
-rw-r--r-- 1 test test 3771 Apr  5  2018 .bashrc
-rw-r--r-- 1 test test  807 Apr  5  2018 .profile

# /etc/passwd文件中已经有test用户的记录了
ubuntu@VM-8-7-ubuntu:~$ cat /etc/passwd | grep -E "ubuntu|root|lighthouse|test"
root:x:0:0:root:/root:/bin/bash
ubuntu:x:500:500:ubuntu,,,:/home/ubuntu:/bin/bash
lighthouse:x:1000:1000::/home/lighthouse:/bin/bash
test:x:1001:1001::/home/test:/bin/sh

如果你想从系统中删除用户,userdel可以满足这个需求。默认情况下,userdel命令会只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。如果加上-r参数,userdel会删除用户的HOME目录以及邮件目录。

Text Only
# userdel命令会只删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件
ubuntu@VM-8-7-ubuntu:~$ sudo userdel test
ubuntu@VM-8-7-ubuntu:~$ ll -al /home/test/
total 20
drwxr-xr-x 2 1001 1001 4096 Jun  4 16:15 ./
drwxr-xr-x 5 root root 4096 Jun  4 16:15 ../
-rw-r--r-- 1 1001 1001  220 Apr  5  2018 .bash_logout
-rw-r--r-- 1 1001 1001 3771 Apr  5  2018 .bashrc
-rw-r--r-- 1 1001 1001  807 Apr  5  2018 .profile
# /etc/passwd中已经找不到test用户的记录
ubuntu@VM-8-7-ubuntu:~$ cat /etc/passwd | grep -E "ubuntu|root|lighthouse|test"
root:x:0:0:root:/root:/bin/bash
ubuntu:x:500:500:ubuntu,,,:/home/ubuntu:/bin/bash
lighthouse:x:1000:1000::/home/lighthouse:/bin/bash

# 再次创建test,用于-r测试
ubuntu@VM-8-7-ubuntu:~$ sudo useradd -m test
useradd: warning: the home directory already exists.
Not copying any file from skel directory into it.
# 创建test后,/etc/passwd中又有test用户记录了
ubuntu@VM-8-7-ubuntu:~$ cat /etc/passwd | grep -E "test"
test:x:1001:1001::/home/test:/bin/sh
ubuntu@VM-8-7-ubuntu:~$ ll -al /home/test/
total 20
drwxr-xr-x 2 test test 4096 Jun  4 16:15 ./
drwxr-xr-x 5 root root 4096 Jun  4 16:15 ../
-rw-r--r-- 1 test test  220 Apr  5  2018 .bash_logout
-rw-r--r-- 1 test test 3771 Apr  5  2018 .bashrc
-rw-r--r-- 1 test test  807 Apr  5  2018 .profile
# userdel -r选项会把/home/test目录删除
ubuntu@VM-8-7-ubuntu:~$ sudo userdel -r test
userdel: test mail spool (/var/mail/test) not found
ubuntu@VM-8-7-ubuntu:~$ ll -al /home/test/
ls: cannot access '/home/test/': No such file or directory

修改用户信息:

  • usermod:修改用户账户的字段,还可以指定主要组以及附加组的所属关系
  • passwd :修改已有用户的密码
  • chpasswd:从文件中读取登录名密码对,并更新密码
  • chage :修改密码的过期日期
  • chfn :修改用户账户的备注信息
  • chsh :修改用户账户的默认登录shell

3.4. /etc/group文件

Linux采用“组权限”的概念,允许多个用户对系统中的对象(比如文件、目录或设备等)共享一组共用的权限。

与用户账户类似,组信息保存在/etc/group文件中:

Text Only
1
2
3
4
ubuntu@VM-8-7-ubuntu:~$ cat /etc/group | grep -E "root:|ubuntu:|lighthouse:"
root:x:0:
ubuntu:x:500:
lighthouse:x:1000:lighthouse

/etc/group文件的字段包含了如下信息:

  • 组名
  • 组密码
  • GID
  • 属于该组的用户列表

系统账户用的组通常会分配低于500的GID值,而用户组的GID则会从500开始分配。

groupadd命令可在系统上创建新组。在创建新组时,默认没有用户被分配到该组。groupadd命令没有提供将用户添加到组中的选项,但可以用usermod命令来弥补这一点。

Text Only
ubuntu@VM-8-7-ubuntu:~$ sudo groupadd shared
ubuntu@VM-8-7-ubuntu:~$ cat /etc/group | grep -E "shared:"
shared:x:1001:
ubuntu@VM-8-7-ubuntu:~$ sudo usermod -G shared ubuntu
ubuntu@VM-8-7-ubuntu:~$ sudo usermod -G shared lighthouse
ubuntu@VM-8-7-ubuntu:~$ cat /etc/group | grep -E "shared:"
shared:x:1001:ubuntu,lighthouse
# groupmod -n 可以修改组名
ubuntu@VM-8-7-ubuntu:~$ sudo groupmod -n sharing shared
ubuntu@VM-8-7-ubuntu:~$ cat /etc/group | grep -E "shared:"
ubuntu@VM-8-7-ubuntu:~$ cat /etc/group | grep -E "sharing:"
sharing:x:1001:ubuntu,lighthouse

修改组名时,GID和组成员不会变,只有组名改变。由于所有的安全权限都是基于GID的,可以随意改变组名而不会影响文件的安全性。

3.5. 文件权限

Text Only
1
2
3
4
5
6
ubuntu@VM-8-7-ubuntu:~$ ll /etc/passwd /etc/shadow
-rw-r--r-- 1 root root   1765 Jun  4 16:22 /etc/passwd
-rw-r----- 1 root shadow 1040 Jun  4 16:22 /etc/shadow
# 查看ubuntu用户属于ubuntu组和sharing组,即不属于root组或shadow组
ubuntu@VM-8-7-ubuntu:~$ groups ubuntu
ubuntu : ubuntu sharing

第一个字符代表对象类型:

  • ``代表文件
  • d代表目录
  • l代表链接
  • c代表字符型设备
  • b代表块设备
  • n代表网络设备

之后有3组三字符的编码,每一组定义了3种访问权限:

  • r代表对象是可读的
  • w代表对象是可写的
  • x代表对象是可执行的
  • ``表示该权限位没有对应的权限

这3组权限依次对应对象的3个安全级别:

  • 对象的属主
  • 对象的属组
  • 其他用户

上面实操中可以看出,/etc/passwd文件属于root用户,ubuntu用户算是“其他用户”,对应的权限为最后一组r--,即ubuntu用户只能读取/etc/passwd,不能修改或执行。同理,ubuntu用户对于/etc/shadow的权限是---,即不能读写或修改。

linux文件权限码:用一位八进制值表征三位rwx权限值

image-20230716154904333

umask用来设“权限掩码。权限掩码是由3个八进制的数字所组成,将现有的存取权限减掉权限掩码后,即可产生建立文件时预设的权限:

Text Only
1
2
3
4
5
6
7
ubuntu@VM-8-7-ubuntu:~/test$ type -a umask
umask is a shell builtin
ubuntu@VM-8-7-ubuntu:~/test$ umask
0002
ubuntu@VM-8-7-ubuntu:~/test$ touch file
ubuntu@VM-8-7-ubuntu:~/test$ ll file
-rw-rw-r-- 1 ubuntu ubuntu 0 Jun  4 21:14 file

对文件来说,全权限的值是666(所有用户都有读和写的权限);而对目录来说,则是777(所有用户都有读、写、执行权限)。所以在上例中,文件一开始的权限是666,减去umask值0002之后,剩下的文件权限就成了664。

在大多数Linux发行版中,umask值通常会设置在/etc/profile启动文件中,不过有一些是设置在/etc/login.defs文件中的(如Ubuntu)

Text Only
ubuntu@VM-8-7-ubuntu:~/test$ cat /etc/login.defs  | grep UMASK
#       UMASK           Default "umask" value.
# UMASK is the default umask value for pam_umask and is used by
# 022 is the "historical" value in Debian for UMASK
# If USERGROUPS_ENAB is set to "yes", that will modify this UMASK default value
UMASK           022
# 通过umask命令之前权限掩码为026
ubuntu@VM-8-7-ubuntu:~/test$ umask 026
# 新文件file1的“其他用户”权限位666-026=640
ubuntu@VM-8-7-ubuntu:~/test$ touch file1
ubuntu@VM-8-7-ubuntu:~/test$ ll
total 16
drwxrwxr-x  4 ubuntu ubuntu 4096 Jun  4 21:47 ./
drwx------ 11 ubuntu ubuntu 4096 Jun  4 16:54 ../
-rw-rw-r--  1 ubuntu ubuntu    0 Jun  4 21:14 file
-rw-r-----  1 ubuntu ubuntu    0 Jun  4 21:47 file1
drwxrwxr-x  2 ubuntu ubuntu 4096 Jun  4 12:43 version1/
drwxrwxr-x  2 ubuntu ubuntu 4096 Jun  4 12:43 version2/

chmod命令用来改变文件和目录的安全性设置。该命令的格式如下:

Text Only
chmod options mode file

mode参数可以使用八进制模式或符号模式进行安全性设置。

还有另外一种形式:

Text Only
[ugoa…][[+-=][rwxXstugo…]
  • 权限施加对象:
  • u代表用户
  • g代表组
  • o代表其他
  • a代表上述所有
  • 权限增加或移除
  • +在现有权限基础上增强权限
  • ``在现有权限基础上移除权限
  • =将权限设置成后面的值
  • 权限内容
  • X:如果对象是目录或者它已有执行权限,赋予执行权限。
  • s:运行时重新设置UID或GID。
  • t:保留文件或目录。
  • u:将权限设置为跟属主一样。
  • g:将权限设置为跟属组一样。
  • o:将权限设置为跟其他用户一样。

例如:

Text Only
ubuntu@VM-8-7-ubuntu:~/test$ ll file1
-rw-r----- 1 ubuntu ubuntu 0 Jun  4 21:47 file1
# chmod直接按八进制设置权限
ubuntu@VM-8-7-ubuntu:~/test$ chmod 666 file1
ubuntu@VM-8-7-ubuntu:~/test$ ll file1
-rw-rw-rw- 1 ubuntu ubuntu 0 Jun  4 21:47 file1
# 给文件所属用户添加可执行权限
ubuntu@VM-8-7-ubuntu:~/test$ chmod u+x file1
ubuntu@VM-8-7-ubuntu:~/test$ ll file1
-rwxrw-rw- 1 ubuntu ubuntu 0 Jun  4 21:47 file1*

4. 重要命令

4.1. FHS标准

常见Linux目录如下,遵循文件系统层次结构标准(Filesystem Hierarchy Standard, FHS)

FHS官网:https://www.pathname.com/fhs/

在FHS中,所有的文件和目录都出现在根目录"/"下,即使他们存储在不同的物理设备中。但是请注意,这些目录中的一些可能或可能不会在Unix系统上出现,这取决于系统是否含有某些子系统,例如X窗口系统的安装与否。

这些目录中的绝大多数都在所有的UNIX操作系统中存在,并且一般都以大致类似的方法使用;然而,这里的描述是针对于FHS的,并未考虑除了Linux平台以外的权威性。

image-20230716155003326

4.2. 文件元数据

  • 文件类型:目录d、文件`、字符型文件c、块设备b`
  • 文件权限
  • 文件的硬链接总数
  • 文件属主的用户名
  • 文件属组的组名
  • 文件的大小
  • 文件上次修改时间
  • 文件名

4.3. 过滤输出

  • 匹配一个字符
  • ``零个或多个字符
  • []选择集
  • !排除在外

疑问:跟正则表达式完全兼容?有没有像fhs一样的业界规范

4.4. 目录使用

  • 如何没有为cd命令指定目标路径,它将切换到用户主目录
  • ls -R递归列出目录,即包含子目录

4.5. 文件类型

file命令

4.6. 文件内容

  • cat
  • more
  • tail
  • Head

4.7. 进程管理

  • ps
  • jobs:可以查看后台进程
  • top
  • Kill

4.8. 磁盘管理

  • mount
  • unmount
  • df
  • du

4.9. 软链接和硬链接

参考:

使用:

Text Only
# 创建新文件
touch file.txt
echo "hello,world" > file.txt

# 创建硬链接
ln file.txt hl_file.txt

# 创建软链接
ln -s file.txt sl_file.txt

# 查看文件详细信息,包括inode号
ls -li

# 输出:
131223 -rw-rw-r-- 2 ubuntu ubuntu 12 Jun  3 17:36 file.txt
131223 -rw-rw-r-- 2 ubuntu ubuntu 12 Jun  3 17:36 hl_file.txt
131241 lrwxrwxrwx 1 ubuntu ubuntu  8 Jun  3 17:36 sl_file.txt -> file.txt

从输出可见:

  • 软链接的文件类型为l,硬链接的文件类型就是普通的文件``
  • 硬链接与源文件的inode号一样,都是131223,而软链接与源文件不同
  • 硬链接与源文件文件大小、权限等元数据信息一致,本质上是指向同一个数据块,软链接文件与源文件本质上是不同的文件

区别:

  • 硬链接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬链接到重要文件,以防止“误删”的功能,由于对应该目录的索引节点有一个以上的连接,假设我们删除了原始的此时文件的内容依然存在,所以只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个链接被删除后,文件的数据块及目录的连接才会被释放,也就是说,文件才会被真正删除。
  • 软链接(也叫符号链接),类似于windows系统中的快捷方式。软链接因其支持挂系统的特性,因此可以节省空间解决空间不足问题,例如某个文件文件系统空间已经用完了,但是现在必须在该文件系统下创建一个新的目录并存储大量的文件,那么可以把另一个剩余空间较多的文件系统中的目录链接到该文件系统中。在对符号文件进行读或写操作的时候,系统会自动把该操作转换为对源文件的操作,但删除链接文件时,系统仅仅删除链接文件,而不删除源文件本身,

image-20230716155019311

软链接

image-20230716155027269

软链接与硬链接的图解:

image-20230716155034504

5. 编写shell脚本


最后更新: 2024-04-14