linux 操作系统考试复习 Shepard-Wang

一 习题

shell 种类

bash,csh,ksh 等

什么是 shell?有什么用?

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。

Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

什么是符号链接?什么是硬链接?他们之间的区别

硬链接

硬链接是文件的别名。从技术上讲,他们公用一个inode(inode中包含了一个文件的所有必要的信息,说inode就是文件也是没有问题的)。

由于linux下的文件是通过索引节点(Inode)来识别文件,硬链接也可以认为是一个指向文件索引节点的指针,系统并不为它重新分配inode。

软连接

软链接是一种特殊的文件类型,其中包含对另一个 文件/目录 以 绝对/相对 路径形式的引用.

软链接可以看做是对一个文件的间接指针,相当于windows下的快捷方式。

创建文件的软链接时,软链接会使用一个新的inode,所以软链接的inode号和文件的inode号不同(表明他们是两个不同的文件),

软链接的inode里存放着指向文件的路径,删除源文件,软链接也无法使用了,因为文件的路径不存在了;删除软链接对原文件没有任何影响。

区别

1、硬链接 和 源文件 是同一个文件;软链接 和 源文件 是2个不同的文件。

2、大部分系统不能创建 目录 的硬链接,软链接没有这个限制。

3、硬链接不能跨文件系统(分区),软链接没有这个限制。

at 作业和 cron 作业的区别

  • cron 用来提交不断循环执行的作业

  • at 用来提交在一段时间后执行的作业,执行完就会自动删除

  1. 每天早上 9 点保存当前登录用户到 useronline 文件

    * 9 * * * who >> useronline
    

    上面是老师给的“标准答案”,但是我的 ubuntu 20.04 中使用 who 命令没有输出。crontab 指令的第一个时间参数我认为应该设置为 0,因为早上 9 点应该属于一个时间点

    0 9 * * * who >> useronline
    
  2. 每周日凌晨 0 点 0 分定期备份 /usr/backup/tmp

    0 0 * * 0 cp -r /usr/backup /tmp
    
  3. 每周五下午 5:30 删除所有临时文件(/tmp 中的所有文件)

    30 5 * * 6 rm -rf /tmp/*
    
  4. 每周日 23:50 将 /data 目录下的所有目录和文件压缩为 backup.tar.gz 文件并归档

    50 23 * * 0 tar -zcvf back.tar.gz /data
    

现有一个windows下使用过的U盘(U盘使用/dev/sda1接口),要求在在此U盘上新建 myfiles 目录,并在此目录下新建一文件 soft, 内容任意,再将该文件复制到/root目录下,最后安全取出U盘,要求写出相关的命令行。

mkdir /mnt/sda1
mount /dev/sda1 /mnt/sda1
cd /mnt/sda1
mkdir myfiles
echo "123">myfiles/soft
cp myfiles/soft /root
cd /
umount /mnt/sda1

用 C 语言编程,打开用户指定文件,将文件内容倒序后再写入该文件。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#define PRINT_ERR(s) \
        { perror(s); return -1; }

int main()
{
    struct stat s;
    if (lstat("at.log", &s) == -1 ) PRINT_ERR("lstat")

    off_t sz = s.st_size;
    if(sz <= 0) 
    {
        printf("empty file\n");
        return 0;
    }

    char* buf = (char*)malloc(sz);
    
    int fd = open("at.log", O_RDWR);
    if(fd == -1) PRINT_ERR("open")
    
    off_t r_num = read(fd, buf, sz);
    if(r_num != sz) PRINT_ERR("read")

    off_t i = 0, j = sz - 1;    
    while(i < j)
    {
        char tmp = buf[i];
        buf[i] = buf[j];
        buf[j] = tmp;
        i++, j--;
    }

    lseek(fd, 0, SEEK_SET);
    off_t w_num = write(fd, buf, sz);
    if(w_num != sz) PRINT_ERR("write")
    
    free(buf);
    close(fd);
    
    return 0;
}

用C语言实现多进程编程,主进程每隔1秒获取当前系统时间写入某文件,子进程打开该文件,读取文件的内容并显示在屏幕上

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>

#define PRINT_ERR(s) \
        { perror(s); return -1; }
#define CTIME_STRLEN 25

int main()
{  
    int st = fork();
    if( st == -1 ) PRINT_ERR("fork")
    else if(st != 0)
    {
        int fd = open("time.txt", O_CREAT | O_WRONLY, 0664);
        if(fd == -1) PRINT_ERR("father open")

        while(1)
        {
            time_t t;
            time(&t);
            char* str_time = ctime(&t);
            write(fd, str_time, strlen(str_time));
            sleep(1);   
        }            
        
        close(fd);
    }
    else
    {
        sleep(1);
        int fd = open("time.txt", O_RDONLY);
        if(fd == -1) PRINT_ERR("child open")
        
        while(1)
        {
           char buf[CTIME_STRLEN];
           read(fd, buf, CTIME_STRLEN);
           write(1, buf, CTIME_STRLEN);
           sleep(1); 
        }

        close(fd);
    }

    
    return 0;
}

这样写其实是不能保证线程安全的。

Shell 编程,判断一个文件是不是块或字符设备文件,如果是则将其复制到 /dev 目录

if test -b file -o -c file
then 
    cp file /dev
fi

编写shell脚本,可以用键盘输入一个学生成绩(百分制),并转换为对应的成绩标准显示,如:优(90-100);良(80-89);中(70-79);及格(60-69);不及格(0-59)

#!/usr/bin/zsh

read num
if [ $num -ge 90 ]
then 
    echo "优秀"
elif [ $num -ge 80 ]
then 
    echo "良好"
elif [ $num -ge 70 ]
then 
    echo "中等"
elif [ $num -ge 60 ]
then 
    echo "及格"
else 
    echo "不及格"
fi

让用户用键盘输入一个数字,程序可以由 1+2 +3+…… 一直累加到用户输入的数为止,并输出算式和计算结果

#!/usr/bin/zsh

read num
i=1
sum=0
while ((i<=num))
do
    let sum+=i
    let i+=1
done

echo $sum

通配符

三种通配符 *?[]

 1. *:匹配任意多个字符  2. ** 匹配任意级别目录(bash 4.0以上版本支持)  3. ?:匹配任一单个字符  4. [chars]:匹配任意一个属于字符集中的字符,chars表示一组字符。  5. [!chars]:匹配任意一个不属于字符集中的字符,chars表示一组字符。  6. [[:class:]] 匹配一个属于指定字符类中的字符,[:class:]表示一种字符类,比如数字、大小写字母等。

  1、[:alnum:]:匹配任意一个字母或者数字,传统Unix写法:a-zA-Z0-9

  2、[:alpha:]:匹配任意一个字母,传统 Unix 写法:a-zA-Z

  3、[:digit:]:匹配任意一个数字,传统 Unix 写法:0-9

  4、[:lower:]:匹配任意一个大写字母,传统 Unix 写法:A-Z

​ 5、[:upper:]:匹配任意一个大写字母,传统 Unix 写法:A-Z。 ​ 6、[:blank:]:空白字符和TAB制表符 ​ 7、[:space:]:包括空白字符、TAB制表符(\t)、换页(\f) ​ 8、[:cntrl:]:所有控制字符 ​ 9、[:graph:]:可打印并可看到的字符。空格是可打印的,但是不是可看到的。
​ 10、[:print:]:所有可打印字符 ​ 11、[:punct:]:所有标点符号,非字母、数字、控制字符和space字符。
​ 12、[:xdigit:]:十六进制数的字符。

❯ ls
file1   file13  file17  file20  file6  filea  filee  filei  filem  fileq  fileu  filey
file10  file14  file18  file3   file7  fileb  filef  filej  filen  filer  filev  filez
file11  file15  file19  file4   file8  filec  fileg  filek  fileo  files  filew
file12  file16  file2   file5   file9  filed  fileh  filel  filep  filet  filex

❯ ls file?
file1  file4  file7  filea  filed  fileg  filej  filem  filep  files  filev  filey
file2  file5  file8  fileb  filee  fileh  filek  filen  fileq  filet  filew  filez
file3  file6  file9  filec  filef  filei  filel  fileo  filer  fileu  filex

❯ ls file*
file1   file13  file17  file20  file6  filea  filee  filei  filem  fileq  fileu  filey
file10  file14  file18  file3   file7  fileb  filef  filej  filen  filer  filev  filez
file11  file15  file19  file4   file8  filec  fileg  filek  fileo  files  filew
file12  file16  file2   file5   file9  filed  fileh  filel  filep  filet  filex

❯ ls file[abc012]
file1  file2  filea  fileb  filec

❯ ls file[\!abc012]
file3  file6  file9  filef  filei  filel  fileo  filer  fileu  filex
file4  file7  filed  fileg  filej  filem  filep  files  filev  filey
file5  file8  filee  fileh  filek  filen  fileq  filet  filew  filez

❯ ls file[:digit:]
filed  fileg  filei  filet
❯ ls file[[:digit:]]
file1  file2  file3  file4  file5  file6  file7  file8  file9
❯ ls file[[:alpha:]]
filea  filec  filee  fileg  filei  filek  filem  fileo  fileq  files  fileu  filew  filey
fileb  filed  filef  fileh  filej  filel  filen  filep  filer  filet  filev  filex  filez

二 shell

环境变量

环境变量说明
PATH指定命令的搜索路径,以冒号为分隔符
HOME指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
HISTFILE命令历史文件
HISTSIZE保存历史命令记录的条数
LOGNAME当前的登录名
HOSTNAME指主机的名称
SHELLShell的全路径名
TERM用户控制终端的类型
PWD当前工作目录的全称
PS1命令基本提示符,对于root用户是“#”,对于普通用户是“$”

系统变量

系统变量说明
$0Shell程序名
` $1-$9 `第1个到第9个命令行参数的值
$*传递给脚本的所有参数,全部参数合为一个字符串
$#传递给脚本的参数的个数
$$ 当前进程的进程ID
$?最后执行的一条命令的退出状态,返回值为0则成功,非0则失败
$!在后台运行的最后一个进程的进程ID

运算

expr

❯ a=3
❯ b=2
❯ expr $a + $b #不能没有空格
5

❯ echo $a + $b
3 + 2
❯ echo a + b
a + b

let

❯ let c=$a+$b
❯ echo $c
5

可以没有 $

❯ let c=a+b
❯ echo $c
5

转义字符

转义符说明
'(单引号)单引号括起来的字符串中,所有的Shell 元字符、通配符都会被关掉,都作为普通字符出现。
"(双引号)双引号括起来的字符串中,如果出现特定的Shell元字符($,,\),则表示这些元字符的基本意义,如$用于变量值替换、(倒引号)用于命令替换、\用于转义单个字符
\(反斜杠)转义,去掉其后紧跟的元字符或通配符的特殊意义

条件测试

Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

文件测试
操作符说明
  
-b file若文件file存在,且为块文件,则条件测试为真,返回结果为0
-c file若文件file存在,且为字符文件,则条件测试为真,返回结果为0
-d file若文件file存在,且为目录文件,则条件测试为真,返回结果为0
-e file若文件file存在,则条件测试为真,返回结果为0
-f file若文件file存在,且为常规文件,则条件测试为真,返回结果为0
-r file若文件file存在并且可读,则条件测试为真,返回结果为0
-w file若文件file存在并且可写,则条件测试为真,返回结果为0
-x file若文件file存在并且可执行,则条件测试为真,返回结果为0
-p file若文件file存在并且是FIFO文件,则条件测试为真,返回结果为0
-s file若文件file存在并且不是空文件,则条件测试为真,返回结果为0
❯ test -x at.log
❯ echo $?
1
❯ test -f at.log -a -x at.log
❯ echo $?
1
❯ test -f at.log -a -w at.log
❯ echo $?
0
❯ echo $?
2
❯ test -e at.log -a -s at.log
❯ echo $?
0
数值测试
参数说明
-eq等于则为真
-ne不等于则为真
-gt大于则为真
-ge大于等于则为真
-lt小于则为真
-le小于等于则为真
#!/usr/bin/zsh

a=1
b=2
c=1
str1="noob$a"
str2='noob$a'

if test $a -eq $b
then
    echo 'a=b'
elif test $a -gt $b
then
    echo 'a>b'
elif test $a -le $c
then
    echo 'a<=c'
else 
    echo 'not known'
fi

a<=c

字符串测试
参数说明
=等于则为真
!=不相等则为真
-z 字符串字符串的长度为零则为真
-n 字符串字符串的长度不为零则为真
#!/usr/bin/zsh

a=1
str1="noob$a"
str2='noob$a'

if test $str1 = $str2
then
    echo 'str1=str2'
else
    echo 'not'
fi

not

逻辑运算

hell 还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为: ! 最高, -a 次之, -o 最低。

| ( exp ) | 圆括号,将表达式分组,优先得到结果。(括号前后有空格并用转义符“(”和“)”) | | ——- | ———————————————————— |

分支和循环

select

#!/usr/bin/zsh

select var in "a" "b" "c" "d"
do
    echo "you answer is $var"
    break
done
❯ ./sh.sh
1) a  2) b  3) c  4) d  
?# 4
you answer is d
❯ ./sh.sh
1) a  2) b  3) c  4) d  
?# a
you answer is 

case

#!/usr/bin/zsh

read num
case $num in
1) echo "you choose 1";;#两个分号
2) echo "you choose 2";;
3) echo "you choose 3";;
*) echo "not know";;
esac

for

#!/usr/bin/zsh

for country in {'china','japan','america'} #花括号内不能有空格
do
    echo $country
done
❯ ./sh.sh
china
japan
america
#!/usr/bin/zsh

for arg 
do
    echo $arg
done
❯ ./sh.sh 1 2 3
1
2
3
#!/usr/bin/zsh

sum=0

for ((i=0;i<100;i++)) #for 和 ( 之间要有空格
do
    let sum+=i
done

echo "sum is $sum"
sum is 4950

while

#!/usr/bin/zsh

sum=0
i=1

while ((i<=100))
do 
    let sum+=i 
    let i+=2
done 

echo "sum is $sum"
❯ ./sh.sh
sum is 2500

break

break n

break 命令后面的整数 n 表示要跳出 n 层循环,默认值为 1。

#!/usr/bin/zsh

while true 
do 
    echo "Input number 1-5"
    read num
    case $num in 
    1|2|3|4|5) echo "you input $num" ;;
    *) echo "you input other" 
    break ;; 
    esac
done

continue

continue n

continue 命令后面的整数 n 表示要提出 n 层循环,默认值为 1。

#!/usr/bin/zsh

for i in {1..10}
do 
    if test $i -eq 4 -o $i -eq 8
    then 
        continue
    else 
        echo $i 
    fi 
done 

三 其他概念

进程管理

进程状态转换

process_stat.png

写时拷贝

cow1.png

cow2.png

fork & vfork

fork.png

进程 exit 方式

exit.png

exit2.png

mmap 映射文件

mmap.png

一些命令

usermod 修改用户帐号的各项设定

Linux usermod命令用于修改用户帐号。

usermod可用来修改用户帐号的各项设定。

语法

usermod [-LU][-c <备注>][-d <登入目录>][-e <有效期限>][-f <缓冲天数>][-g <群组>][-G <群组>][-l <帐号名称>][-s <shell>][-u <uid>][用户帐号]

参数说明

  • -c<备注>  修改用户帐号的备注文字。
  • -d登入目录>  修改用户登入时的目录。
  • -e<有效期限>  修改帐号的有效期限。
  • -f<缓冲天数>  修改在密码过期后多少天即关闭该帐号。
  • -g<群组>  修改用户所属的群组。
  • -G<群组>  修改用户所属的附加群组。
  • -l<帐号名称>  修改用户帐号名称。
  • -L  锁定用户密码,使密码无效。
  • -s  修改用户登入后所使用的shell。
  • -u  修改用户ID。
  • -U  解除密码锁定。

实例

更改登录目录

# usermod -d /home/hnlinux root

改变用户的uid

# usermod -u 777 root

chgrg 更改文件属组

语法:

chgrp [-R] 属组名 文件名

参数选项

  • -R:递归更改文件属组,就是在更改某个目录文件的属组时,如果加上-R的参数,那么该目录下的所有文件的属组都会更改。

chown 更改文件属主,也可以同时更改文件属组

语法:

chown [–R] 属主名 文件名
chown [-R] 属主名:属组名 文件名

进入 /root 目录(~)将install.log的拥有者改为bin这个账号:

[root@www ~] cd ~
[root@www ~]# chown bin install.log
[root@www ~]# ls -l
-rw-r--r--  1 bin  users 68495 Jun 25 08:53 install.log

将install.log的拥有者与群组改回为root:

[root@www ~]# chown root:root install.log
[root@www ~]# ls -l
-rw-r--r--  1 root root 68495 Jun 25 08:53 install.log
❯ ll -l /home
total 12K
drwxr-xr-x 3 admin admin 4.0K Nov  2  2021 admin
drwxr-xr-x 2 root  root  4.0K May 25 19:06 hc
drwxr-xr-x 3 wxc   wxc   4.0K Apr 21 22:31 wxc

❯ chown hc:hc /home/hc

❯ ll /home
total 12K
drwxr-xr-x 3 admin admin 4.0K Nov  2  2021 admin
drwxr-xr-x 2 hc    hc    4.0K May 25 19:06 hc
drwxr-xr-x 3 wxc   wxc   4.0K Apr 21 22:31 wxc

chmod 更改文件9个属性

数字方式

Linux文件属性有两种设置方法,一种是数字,一种是符号。

Linux 文件的基本权限就有九个,分别是 owner/group/others(拥有者/组/其他) 三种身份各有自己的 read/write/execute 权限。

先复习一下刚刚上面提到的数据:文件的权限字符为: -rwxrwxrwx , 这九个权限是三个三个一组的!其中,我们可以使用数字来代表各个权限,各权限的分数对照表如下:

  • r:4
  • w:2
  • x:1

每种身份(owner/group/others)各自的三个权限(r/w/x)分数是需要累加的,例如当权限为: -rwxrwx— 分数则是:

  • owner = rwx = 4+2+1 = 7
  • group = rwx = 4+2+1 = 7
  • others= --- = 0+0+0 = 0

所以等一下我们设定权限的变更时,该文件的权限数字就是 770。变更权限的指令 chmod 的语法是这样的:

 chmod [-R] xyz 文件或目录

选项与参数:

  • xyz : 就是刚刚提到的数字类型的权限属性,为 rwx 属性数值的相加。
  • -R : 进行递归(recursive)的持续变更,以及连同次目录下的所有文件都会变更

举例来说,如果要将 .bashrc 这个文件所有的权限都设定启用,那么命令如下:

[root@www ~]# ls -al .bashrc
-rw-r--r--  1 root root 395 Jul  4 11:45 .bashrc
[root@www ~]# chmod 777 .bashrc
[root@www ~]# ls -al .bashrc
-rwxrwxrwx  1 root root 395 Jul  4 11:45 .bashrc

那如果要将权限变成 -rwxr-xr– 呢?那么权限的分数就成为 [4+2+1][4+0+1][4+0+0]=754。

符号方式

还有一个改变权限的方法,从之前的介绍中我们可以发现,基本上就九个权限分别是:

  • user:用户
  • group:组
  • others:其他

那么我们就可以使用 u, g, o 来代表三种身份的权限。

此外, a 则代表 all,即全部的身份。读写的权限可以写成 r, w, x,也就是可以使用下表的方式来看:

chmodu g o a+(加入) -(除去) =(设定)r w x文件或目录
     

如果我们需要将文件权限设置为 -rwxr-xr– ,可以使用 chmod u=rwx,g=rx,o=r 文件名 来设定:

#  touch test1    // 创建 test1 文件
# ls -al test1    // 查看 test1 默认权限
-rw-r--r-- 1 root root 0 Nov 15 10:32 test1
# chmod u=rwx,g=rx,o=r  test1    // 修改 test1 权限
# ls -al test1
-rwxr-xr-- 1 root root 0 Nov 15 10:32 test1

而如果是要将权限去掉而不改变其他已存在的权限呢?例如要拿掉全部人的可执行权限,则:

#  chmod  a-x test1
# ls -al test1
-rw-r--r-- 1 root root 0 Nov 15 10:32 test1
❯ chmod 777 /home/hc
❯ ll /home/hc
total 0
❯ ll /home/hc -d
drwxrwxrwx 2 hc hc 4.0K May 25 19:06 /home/hc
❯ chmod o-w /home/hc
❯ ll /home/hc -d
drwxrwxr-x 2 hc hc 4.0K May 25 19:06 /home/hc