[MIT公开课(计算机教育中缺失的一课)] 1.Overview+Shell

(该系列文章大部分内容来源于MIT课程笔记,加入了个人的理解、原笔记中没有的细节和其他的需要理解的内容,公开课地址:https://www.bilibili.com/video/BV14E411J7n2?p=1

下一讲:Shell工具与脚本



The Shell

1.Shell是什么?

如今的计算机有着多种多样的交互接口让我们可以进行指令的的输入,从炫酷的图像用户界面(GUI),语音输入甚至是AR/VR都已经无处不在。 这些交互接口可以覆盖80%的使用场景,但是它们也从根本上限制了您的操作方式——你不能点击一个不存在的按钮或者是用语音输入一个还没有被录入的指令。 为了充分利用计算机的能力,我们不得不回到最根本的方式,使用文字接口:Shell。虽然各种平台支持不同的Shell,但是其核心功能都是一样的:它允许你执行程序,输入并获取某种半结构化的输出。

这里我们使用Bourne Again SHell, 简称 “bash” (现在流行的zsh是兼容bash的,MIT老师用的是bash,博主演示的是在Mac下使用zsh)

在mac终端切换bash和zsh:
切换到bash:chsh -s /bin/bash或直接输入bash
切换到zsh:chsh -s /bin/zsh或直接输入zsh

重启终端后有效(后面两个方法不需要重启)。


2.使用shell

当您打开终端时,您会看到一个提示符,它看起来一般是这个样子的:

missing:~$ 

这是shell最主要的文本接口。它告诉你,你的主机名是 missing 并且您当前的工作目录或者说您当前所在的位置是~ (表示 “home”)。 $符号表示您现在的身份不是root用户(稍后会介绍)。在这个提示符中,您可以输入 命令 ,命令最终会被shell解析。最简单的命令是执行一个程序:

missing:~$ date
Fri 10 Jan 2020 11:49:31 AM EST
missing:~$ cal # 输出当月日历
      九月 2020         
日 一 二 三 四 五 六  
       1  2  3  4  5  
 6  7  8  9 10 11 12  
13 14 15 16 17 18 19  
20 21 22 23 24 25 26 
27 28 29 30  

missing:~$ df # 查看磁盘剩余空间的数量
missing:~$ free # 查看空闲内存的数量

在这里插入图片描述

echo

我们可以在执行命令的同时向程序传递 参数 :

missing:~$ echo hello
hello
missing:~$ 

上例中,我们让shell执行 echo ,同时指定参数hello,echo 程序将该参数打印出来。

echo还可以将shell当做计算器使用,在算术表达式中空格并不重要,并且表达式可以嵌套:

echo $((expression))

举例:

➜  Downloads  echo Five divided by two equals $((5/2))
Five divided by two equals 2

参数展开

shell是如何知道去哪里寻找 dateecho 的呢?其实,类似于Python or Ruby,shell是一个编程环境,所以它具备变量、条件、循环和函数。当你在shell中执行命令时,您实际上是在执行一段shell可以解释执行的简短代码。如果你要求shell执行某个指令,但是该指令并不是shell所了解的编程关键字,那么它会去咨询环境变量 $PATH,它会列出当shell接到某条指令时,进行程序搜索的路径;叫做 “USER” 的变量包含你的用户名。

missing:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

missing:~$ which echo
/bin/echo

missing:~$ /bin/echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

➜  Downloads  echo $USER   
lilhoe

当我们执行 echo 命令时,shell了解到需要执行 echo 这个程序,随后它便会在$PATH中搜索由:所分割的一系列目录,基于名字搜索该程序。当找到该程序时便执行(假定该文件是 可执行程序,后续课程将详细讲解)。确定某个程序名代表的是哪个具体的程序,可以使用 which 程序。我们也可以绕过 $PATH,通过直接指定需要执行的程序的路径来执行该程序。

要查看有效的变量列表,可以试试这个:

printenv | less

引用

➜  Downloads  echo this is a        test
this is a test

➜  Downloads  echo The total is $100.00
The total is .00

shell基于空格分割命令并进行解析,在第一个例子中,shell 利用单词分割删除掉 echo 命令的参数列表中多余的空格。在第二个 例子中,参数展开把 $1 的值替换为一个空字符串,因为 1 是没有定义的变量。shell 提供了一 种叫做引用的机制,来有选择地禁止不需要的展开。

  • 双引号: 如果你把文本放在双引号中,shell 使用的特殊字 符,都失去它们的特殊含义,被当作普通字符来看待。有几个例外:$\(反斜杠),和 (上单引号)。这意味着单词分割(内嵌的空格也不会被当作界定符,它们成为参数的一部分)、路径名展开、波浪线展开和花括号展开都将失效,然而参数展开、 算术展开和命令替换仍然执行。使用双引号,我们可以处理包含空格的文件名(当然也可以不用双引号而用\转义空格)。

  • 单引号:禁止所有的展开。

# 无引用,双引号和单引号的比较
[me@linuxbox ~]$ echo text ~/*.txt {
    
    a,b} $(echo foo) $((2+2)) $USER text 
/home/me/ls-output.txt a b foo 4 me

[me@linuxbox ~]$ echo "text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER" text 
~/*.txt {
    
    a,b} foo 4 me

[me@linuxbox ~]$ echo 'text ~/*.txt {a,b} $(echo foo) $((2+2)) $USER' text 
~/*.txt {
    
    a,b} $(echo foo) $((2+2)) $USER

确定文件类型

  • Linux关于文件名的重要规则:
  1. 以 “.” 字符开头的文件名是隐藏文件ls命令不能列出它们,用ls -a 命令就可以了。当你创建帐号后,几个配置帐号的隐藏文件被放置在你的home目录下。稍后,我们会仔细研究一些隐藏文件,来定制你的系统环境。另外, 一些应用程序也会把它们的配置文件以隐藏文件的形式放在你的家目录下面。

  2. Linux 没有“文件扩展名”的概念,不像其它一些系统。可以用你喜欢的任何 名字来给文件起名。文件内容或用途由其它方法来决定。虽然类 Unix 的操作 系统,不用文件扩展名来决定文件的内容或用途,但是有些应用程序会。

  3. 虽然 Linux 支持长文件名,文件名可能包含空格,标点符号,但标点符号仅限 使用“.”,“-”,下划线。最重要的是,不要在文件名中使用空格。如果你想表 示词与词间的空格,用下划线字符来代替。

基于上述第三点,我们需要确定文件类型,使用下面file语句,打印出文件内容的简单描述:

file filename

# 举例:
~/Downloads file paper.tex  
paper.tex: LaTeX 2e document text, ASCII text

3.在shell中导航

shell中的路径是一组被分割的目录,在 Linux 和 macOS 上使用 / 分割,而在Windows上是\。路径 /代表的是系统的根目录,所有的文件夹都包括在这个路径之下(Linux系统)。当前工作目录可以使用 pwd命令来获取。此外,切换目录需要使用 cd 命令。在路径中,. 表示的是当前目录,而.. 表示上级目录:

missing:~$ pwd
/home/missing
missing:~$ cd /home
missing:/home$ pwd
/home
missing:/home$ cd ..
missing:/$ pwd
/
missing:/$ cd ./home
missing:/home$ pwd
/home
missing:/home$ cd missing
missing:~$ pwd
/home/missing
missing:~$ ../../bin/echo hello
hello

通过cd -命令可以回到上次的目录环境下,cd ~默认回到根目录:

lilhoe@LilHoedeMacBook-Pro ~ % cd /Users/lilhoe/Downloads                
lilhoe@LilHoedeMacBook-Pro Downloads % pwd
/Users/lilhoe/Downloads
lilhoe@LilHoedeMacBook-Pro Downloads % cd ~
lilhoe@LilHoedeMacBook-Pro ~ % pwd 
/Users/lilhoe
lilhoe@LilHoedeMacBook-Pro ~ % cd - 
~/Downloads
lilhoe@LilHoedeMacBook-Pro Downloads % pwd
/Users/lilhoe/Downloads
lilhoe@LilHoedeMacBook-Pro Downloads % 

为了查看指定目录下包含哪些文件,我们使用ls 命令:

missing:~$ ls
missing:~$ cd ..
missing:/home$ ls
missing
missing:/home$ cd ..
missing:/$ ls
bin
boot
dev
etc
home
...

除非我们利用第一个参数指定目录,否则ls会打印当前目录下的文件。大多数的命令接受标记和选项(带有值的标记),它们以- 开头,并可以改变程序的行为。通常,在执行程序时使用-h-help标记可以打印帮助信息,以便了解有哪些可用的标记或选项。例如,ls -help 的输出如下(zsh):

lilhoe@LilHoedeMacBook-Pro ~ % ls -help
total 0
drwx------@  3 lilhoe  staff    96B  2 15  2020 Applications/
drwx------@ 25 lilhoe  staff   800B  8 17 18:27 Desktop/
 0: group:everyone deny delete
drwx------@ 42 lilhoe  staff   1.3K  8 26 14:23 Documents/
 0: group:everyone deny delete
drwx------@ 36 lilhoe  staff   1.1K  8 26 18:50 Downloads/
 0: group:everyone deny delete
drwx------@ 80 lilhoe  staff   2.5K  7  6 11:58 Library/
 0: group:everyone deny delete
drwx------+  6 lilhoe  staff   192B  7  3 15:57 Movies/
 0: group:everyone deny delete
drwx------+  8 lilhoe  staff   256B  5 17 15:53 Music/
 0: group:everyone deny delete
drwx------+  7 lilhoe  staff   224B  2 25  2020 Pictures/
 0: group:everyone deny delete
drwxr-xr-x+  4 lilhoe  staff   128B  1  1  1970 Public/
 0: group:everyone deny delete
drwxr-xr-x   9 lilhoe  staff   288B  7 21 19:02 wekafiles/
lilhoe@LilHoedeMacBook-Pro ~ % 

这个参数可以打印出更加详细地列出目录下文件或文件夹的信息。首先,本行第一个字符d 表示 missing 是一个目录。然后接下来的九个字符,每三个字符构成一组。 (rwx).们分别代表了文件所有者(missing),用户组 (users) 以及其他所有人具有的权限。其中 -表示该用户不具备相应的权限。从上面的信息来看,只有文件所有者可以修改(w) , missing 文件夹 (例如,添加或删除文件夹中的文件)。为了进入某个文件夹,用户需要具备该文件夹以及其父文件夹的“搜索”权限(以“可执行”:x)权限表示。为了列出它的包含的内容,用户必须对该文件夹具备读权限(r)。对于文件来说,权限的意义也是类似的。注意,/bin目录下的程序在最后一组,即表示所有人的用户组中,均包含x权限,也就是说任何人都可以执行这些程序。

还有的命令是需要掌握的,例如 mv (用于重命名或移动文件)、 cp(拷贝文件)、rm(删除文件)以及 mkdir(新建文件夹)。mvcp都接收两个参数,第一个为旧路径(或文件名),第二个为新路径(或文件名)。rmmkdir接收一个参数,在Linux下,删除默认是非递归的,所以不能用rm指令删除一个文件夹,可以传递一个-r来递归删除(详情查看man rm手册)。另一种删除文件夹的安全命令:rmdir,只有当文件夹为空时才允许删除。

lilhoe@LilHoedeMacBook-Pro Downloads % mv 课表.numbers kebiao.numbers
lilhoe@LilHoedeMacBook-Pro Downloads % cp kebiao.numbers /Users/lilhoe/Desktop/Kebiao.numbers
lilhoe@LilHoedeMacBook-Pro Downloads % mkdir lilhoe
lilhoe@LilHoedeMacBook-Pro Downloads % rm kebiao.numbers
lilhoe@LilHoedeMacBook-Pro Downloads % mkdir hisd
lilhoe@LilHoedeMacBook-Pro Downloads % rmdir hisd
lilhoe@LilHoedeMacBook-Pro Downloads %

如果您想要知道关于程序参数、输入输出的信息,亦或是想要了解它们的工作方式,请试试 man 这个程序。它会接受一个程序名作为参数,然后将它的文档(用户手册)展现给您。注意,使用q 可以退出该程序(mac的terminal使用:q只是退出修改模式,需要键入:wq才会保存退出)。

man ls

在这里插入图片描述


4.重定向

在shell中,程序有两个主要的“流”:它们的输入流和输出流。 通常,一个程序的输入输出流都是您的终端。也就是,键盘作为输入,显示器作为输出。 但是,我们也可以重定向这些流!

标准输出重定向

最简单的重定向是< file> file。这两个命令可以将程序的输入输出流分别重定向到文件:

missing:~$ echo hello > hello.txt
missing:~$ cat hello.txt
hello
missing:~$ cat < hello.txt
hello
missing:~$ cat < hello.txt > hello2.txt
missing:~$ cat hello2.txt
hello

<表示重定向该该文件的内容作为输入,>表示将该程序的输出重定向为该文件的内容,cat打印文件内容,cat < hello.txt > hello2.txt可以代替cp命令来复制文件。

还可以使用 >> 来向一个文件追加内容,而>是覆盖输出:

missing:~$ cat < hello.txt >> hello2.txt
missing:~$ cat hello2.txt
hello
hello

由于>是覆盖输出,我们则可以使用>文件名来清空文件或者创建一个新的空文件。

标准错误重定向

一个程序可以在几个编号的文件流中的任一个上产生输出。虽然我们已经将这些文件流的 前三个称作标准输入、输出和错误,shell 内部分别将其称为文件描述符 0、1 和 2。因为标准错误和文件描述符 2 一样,我们用这种 表示法来重定向标准错误:

➜  demo2 git:(master)ls -l /bin/sgd 2>ls-error.txt # 这里将ls命令操作在一个不存在的文件夹上

➜  demo2 git:(master)less ls-error.txt 
ls: /bin/sgd: No such file or directory
ls-error.txt (END)

文件描述符 “2”,紧挨着放在重定向操作符之前,来执行重定向标准错误到文件 ls-error.txt 任务。

重定向标准输出和错误到同一个文件

有两种方法来完成任务。

  1. 传统的方法,在旧版本 shell 中也有效:
[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt 2>&1

使用这种方法,我们完成两个重定向。首先重定向标准输出到文件 ls-output.txt,然后重定 向文件描述符 2(标准错误)到文件描述符 1(标准输出)使用表示法 2>&1。

注意重定向的顺序安排非常重要。标准错误的重定向必须总是出现在标准输出重定向之后, 要不然它不起作用。上面的例子,重定向标准错误到文件 ls-output.txt,但是如果命令顺序改为:2>&1 >ls-output.txt,则标准错误定向到屏幕。

  1. 更精简合理的方法来执行这种联合的重定向:
[me@linuxbox ~]$ ls -l /bin/usr &> ls-output.txt

在这个例子里面,我们使用单单一个表示法 &> 来重定向标准输出和错误到文件 ls- output.txt。

标准输入重定向

cat——连接文件

cat 命令读取一个或多个文件,然后复制它们到标准输出,显示文件而没有分页。

cat 经常被用来显示简短的文本文件。因为 cat 可以接受不只一个文件作为参数,所以它也可以用来把文件连接在一起。比方说我们下载了一个大型文件,这个文件被分离成多个部分(USENET中的多媒体文件经常以这种方式分离),我们想把它们连起来:

cat movie.mpeg.0* > movie.mpeg

因为通配符总是以有序的方式展开,所以这些参数会以正确顺序安排。

如果我们输入不带参数的 “cat” 命令,会发生什么呢:

➜  Downloads  cat    

它会从标准输入读入数据,又因为标准输入默认情况下连接到键盘,它正在等待我们输入数据。输入完成,键入Ctrl-d,来告诉 cat,在标准输入中,它已经到达文件末尾(EOF)。由于没有文件名参数,cat 复制标准输入到标准输出,所以我们看到文本行重复出现。我们可以使用这种行为来创建简短的文本文件,例如:

➜  Downloads  cat > hello.txt  # 等待键盘输入
djwhfwhfghroagvhpire
➜  Downloads  cat hello.txt  # 查看文件内容
djwhfwhfghroagvhpire

管道重定向

使用管道( pipes ),我们能够更好的利用文件重定向。|操作符允许我们将一个程序的输出(管道左侧)和另外一个程序的输入(管道右侧)建立联系。head 命令打印文件的前十行,而 tail命令打印文件的后十行。默认情况下,两个命令都打印十行文本, 但是可以通过 -n 选项来调整命令打印的行数。

missing:~$ ls -l / | tail -n1 # 只打印输出的最后一行
drwxr-xr-x 1 root  root  4096 Jun 20  2019 var

missing:~$ curl --head --silent google.com | grep --ignore-case content-length | cut --delimiter=' ' -f2
219

tail 有一个选项允许你实时地浏览文件。当观察日志文件的进展时,这很有用,因为它们同时在被写入。在以下的例子里,我们要查看目录/var/log 里面的信息文件。在一些 Linux 发行版中,要求有超级用户权限才能阅读这些文件,因为文件/var/log/messages 可能包含安全信息。

[me@linuxbox ~]$ tail -f /var/log/messages
Feb 8 13:40:05 twin4 dhclient: DHCPACK from 192.168.1.1 ....

使用 -f”选项,tail 命令继续监测这个文件,当新的内容添加到文件后,它们会立即出现在屏幕上。

管道通常把多个命令放在一起使用,以这种方式使用的命令叫做过滤器。例如uniq命令可以从数据列表中删除任何重复行。如果我们想看到重复的数据列表,让 uniq 命令带上 -d选项,例如:

ls /bin /usr/bin | sort | uniq -d | less

处理不需要的输出

这种情况尤其适用于错误和状态信息。系统通过重定向输出结果到一个叫做 /dev/null的特殊文件,为我们提供了解决问题的方法。这个文件是系统设备,叫做位存储桶(bit bucket),它可以接受输入,并且对输入不做任何处理。为了隐瞒命令错误信息,我们这样做:

[me@linuxbox ~]$ ls -l /bin/usr 2> /dev/null

5.链接

硬链接

创建硬链接:

ln file link

与更加现代的符号链接相比,硬链接是最初 Unix 创建链接的方式。每个文件默认会有一个硬 链接,这个硬链接给予文件名字。我们每创建一个硬链接,就为一个文件创建了一个额外的目 录项。硬链接有两个重要局限性:

  1. 一个硬链接不能关联它所在文件系统之外的文件。这是说一个链接不能关联与链接本身不在同一个磁盘分区上的文件。
  2. 一个硬链接不能关联一个目录。

一个硬链接和文件本身没有什么区别。不像符号链接,当你列出一个包含硬链接的目录内容时,你会看到没有特殊的链接指示说明。当一个硬链接被删除时,这个链接被删除,但是文件本身的内容仍然存在(这是说,它所占的磁盘空间不会被重新分配),直到所有关联这个文件的链接都删除掉。

符号链接

在我们到处查看时,我们可能会看到一个目录,列出像这样的一条信息:

lrwxrwxrwx 1 root root 11 2007-08-11 07:34 libc.so.6 -> libc-2.6.so

注意看,为何这条信息第一个字符是“l”,并且有两个文件名呢?这是一个特殊文件,叫做符号链接(也称为软链接或者 symlink )。在大多数“类 Unix”系统中,有可能一个文件被多个文件名所指向。

一个叫做libc.so.6的符号链接, 指向一个叫做libc-2.6.so的共享库文件。这意味着,寻找文件ibc.so.6的 程序,实际上得到是文件libc-2.6.so,常用于版本控制。

创建符号链接是为了克服硬链接的局限性。符号链接生效,是通过创建一个特殊类型的文件, 这个文件包含一个关联文件或目录的文本指针。

一个符号链接指向一个文件,而且这个符号链接本身与其它的符号链接几乎没有区别。例如,如果你往一个符号链接里面写入东西,那么相关联的文件也被写入。然而,当你删除一个符号链接时,只有这个链接被删除,而不是文件自身。如果先于符号链接删除文件,这个链接仍然存在,但是不指向任何东西。在这种情况下,这个链接被称为坏链接。在许多实现中,ls 命令会以不同的颜色展示坏链接,比如说红色,来显示它们的存在。

对于符号链接,有一点值得记住,执行的大多数文件操作是针对链接的对象,而不是链接本 身。而rm命令是个特例。当你删除链接的时候,删除链接本身,而不是链接的对象。

ln语句可以创建符号链接:

ln -s itemname linkname

创建符号链接,“item” 可以是一个文件或是一个目录。


6.权限

id—— 找到关于你自己身份的信息

➜  Downloads  id 
uid=501(lilhoe) gid=20(staff) 
groups=20(staff),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),701(com.apple.sharepoint.group.1),33(_appstore),100(_lpoperator),204(_developer),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae)

那么这些信息来源于哪里呢?像 Linux 系统中的许多东西一样,来自一系列的文本文件。 用户帐户定义在/etc/passwd文件里面,用户组定义在/etc/group文件里面。当用户帐户和用户组创建以后,这些文件随着文件/etc/shadow的变动而修改,文件/etc/shadow包含了关于用 户密码的信息。对于每个用户帐号,文件/etc/passwd定义了用户(登录)名、uidgid、帐号的真实姓名、家目录和登录 shell。如果你查看一下文件/etc/passwd和文件/etc/group 的内容, 你会注意到除了普通用户帐号之外,还有超级用户(uid 0)帐号和各种各样的系统用户。

chmod——修改权限

只有文件的所有者或者超级用户 才能更改文件或目录的模式。chmod 命令支持两种不同的方法来改变文件模式:八进制数字表示法或符号表示法。

  • 八进制数字表示法:

通过使用 3 个八进制数字,我们能够设置文件所有者、用户组和其他人的权限:
在这里插入图片描述

➜  Downloads  touch test.txt
➜  Downloads  ls -l test.txt 
-rw-r--r--  1 lilhoe  staff  0  9  7 15:46 test.txt
➜  Downloads  chmod 600 test.txt  
➜  Downloads  ls -l test.txt    
-rw-------  1 lilhoe  staff  0  9  7 15:46 test.txt

通过传递参数“600”,我们能够设置文件所有者的权限为读写权限,而删除用户组和其他人 的所有权限。虽然八进制到二进制的映射看起来不方便,但通常只会用到一些常见的映射关系: 7 (rwx),6 (rw-),5 (r-x),4 (r–),和 0 (-–)。

  • 符号表示法:

符号表示法分为三部分:更改会影响谁,要执行哪个操作,要设置哪种权限。

  1. 通过字符“u”、“g”、“o”和“a”的组合来指定要影响的对象:
    在这里插入图片描述

如果没有指定字符,则假定使用 all。执行的操作可能是一个+字符,表示加上一个权限,一个-,表示删掉一个权限,或者是一个=,表示只有指定的权限可用,其它所有的权限被删除。

  1. 权限由“r”、“w”和“x”来指定:
    在这里插入图片描述

umask——设置默认权限

umask 命令使用八进制表示法来表达从文件模式属性中删除一个 位掩码,举例:

➜  Downloads  rm -f test.txt 
              
➜  Downloads  umask    
022 (另一个常用值是002)

➜  Downloads  > test.txt

➜  Downloads  cat test.txt      

➜  Downloads  ls -l test.txt
-rw-r--r--  1 lilhoe  staff  4  9  7 15:56 test.txt

我们可以看到文件所有者和用户组都得到读权限和写权限,而其他人只是得到读权限。其他人没有得到写权限的原因是由掩码值决定的。重复我们的实验,这次自己设置掩码值:

➜  Downloads  rm test.txt 
➜  Downloads  umask 0000
➜  Downloads  touch foo.txt            
➜  Downloads  ls -l foo.txt 
-rw-rw-rw-  1 lilhoe  staff  0  9  7 16:00 foo.txt

为了弄明白 这是怎么回事,我们需要看一下掩码的八进制形式:

在这里插入图片描述
此刻先忽略掉开头的三个零(我们一会儿再讨论),注意掩码中若出现一个数字 1,则删除文件模式中和这个 1 在相同位置的属性,在这是指其他人的写权限。这就是掩码要完成的任务。掩码的二进制形式中,出现数字 1 的位置,相应地关掉一个文件模式属性。

当你实验完成之后,要记得清理现场:

➜  Downloads  rm foo.txt;umask 0022 

虽然我们通常看到一个八进制的权限掩码用三位数字来表示,但是还有其它较少用到的权限设置。

其中之一是 setuid 位(八进制 4000)。当应用到一个可执行文件时,它把有效用户 ID 从真正的用户(实际运行程序的用户)设置成程序所有者的 ID。这种操作通常会应用到一些由超级用户所拥有的程序。当一个普通用户运行一个程序,这个 程序由根用户 (root) 所有,并且设置了setuid位,这个程序运行时具有超级用户的特权,这样程序就可以访问普通用户禁止访问的文件和目录。很明显,因为这会引起安全方面的问题,所有可以设置 setuid 位的程序个数,必须控制在绝对小的范围内。

第二个是 setgid 位(八进制 2000),这个相似于 setuid 位,把有效用户组 ID 从 真正的用户组 ID 更改为文件所有者的组 ID。如果设置了一个目录的 setgid位,则目录中新创建的文件具有这个目录用户组的所有权,而不是文件创建者所属用户组的所有权。对于共享目录来说,当一个普通用户组中的成员,需要访问共享目录中的所有文件,而不管文件所有者的主用户组时,那么设置setgid 位很有用处。

第三个是sticky位(八进制 1000)。这个继承于 Unix,在 Unix 中,它可能把一个可执行文件标志为“不可交换的”。在 Linux 中,会忽略文件的 sticky 位,但是如果一个目录设置了 sticky 位,那么它能阻止用户删除或重命名文件,除非用户是这个目录的所有者,或者是文件所有者,或是超级用户。这个经常用来控制访问共享目录,比方说/tmp

使用 chmod 命令和符号表示法来设置这些特殊的权限:

  1. 授予一个程序 setuid 权限:chmod u+s program
  2. 授予一个目录 setgid 权限:chmod g+s dir
  3. 授予一个目录 sticky 权限:chmod +t dir

当浏览ls命令的输出结果时,你可以确认这些特殊权限,例如:

  1. 一个程序被设置为 setuid 属性: -rwsr-xr-x
  2. 具有 setgid 属性的目录: drwxrwsr-x
  3. 设置了 sticky 位的目录: drwxrwxrwt

su —— 以其他用户身份和组 ID 运行一个 shell

su [-[l]] [user]  # macbook用户切换时需要在最前面加上sudo

如果包含 -l 选项,那么会为指定用户启动一个需要登录的 shell。这意味着会加载此用户的 shell 环境,并且工作目录会更改到这个用户的home目录。这通常是我们所需要的。如果不指 定用户,那么就假定是超级用户。注意(不可思议地),选项 -l 可以缩写为-,这是经常用 到的形式。启动超级用户的 shell,我们可以这样做:

➜  Downloads  sudo su -                    
Password:
LilHoedeMacBook-Pro:~ root# 

当工作完成后,输入 “exit”,则返回到原来的 shell:

LilHoedeMacBook-Pro:~ root# exit
logout
➜  Downloads  

sudo——超级用户

对于大多数的类Unix系统,有一类用户是非常特殊的,那就是:根用户(root用户)。 在上面的输出结果中,根用户几乎不受任何限制,他可以创建、读取、更新和删除系统中的任何文件。 通常在我们并不会以根用户的身份直接登录系统,因为这样可能会因为某些错误的操作而破坏系统。 取而代之的是我们会在需要的时候使用 sudo命令。顾名思义,它的作用是让您可以以su(super user 或 root的简写)的身份do一些事情。 当您遇到拒绝访问(permission denied)的错误时,通常是因为此时您必须是根用户才能操作。

在Shell中,在用户名后的$(如果采用的是默认的命令行提示符)表示的是以普通用户的身份运行,想要通过root运行,则需要输入sudo su命令,此时变成了#符号,表示是通过超级用户(root)运行。

susudo之间的一个重要区别是sudo不会重新启动一个 shell,也不会加载另一个用户的shell 运行环境。

有一件事情是必须作为root用户才能做的,那就是向sysfs 文件写入内容。系统被挂载在/sys下, sysfs 文件则暴露了一些内核(kernel)参数。 因此,您不需要借助任何专用的工具,就可以轻松地在运行期间配置系统内核。(Windows or macOS没有这个文件)

例如,您笔记本电脑的屏幕亮度写在 brightness 文件中,它位于:

/sys/class/backlight

通过将数值写入该文件,我们可以改变屏幕的亮度。现在,蹦到您脑袋里的第一个想法可能是:

$ sudo find -L /sys/class/backlight -maxdepth 2 -name '*brightness*'
/sys/class/backlight/thinkpad_screen/brightness
$ cd /sys/class/backlight/thinkpad_screen
$ sudo echo 3 > brightness
An error occurred while redirecting file 'brightness'
open: Permission denied

我们得到了一个错误信息。我们已经使用了 sudo 命令!|、>、和 < 是通过shell执行的,而不是被各个程序单独执行。 echo 等程序并不知道|的存在,它们只知道从自己的输入输出流中进行读写。 对于上面这种情况, shell (权限为您的当前用户) 在设置 sudo echo 前尝试打开 brightness文件并写入,但是系统拒绝了shell的操作因为此时shell不是root用户。

明白这一点后,我们可以这样操作:

$ echo 3 | sudo tee brightness

因为打开/sys 文件的是tee这个程序,并且该程序以root权限在运行,因此操作可以进行。 这样就可以在/sys中愉快地玩耍了,例如修改系统中各种LED的状态(路径可能会有所不同):

$ echo 1 | sudo tee /sys/class/leds/input6::scrolllock/brightness

chown —— 更改文件所有者和用户组

使用这个命令需要超级用户权限:

chown [owner][:[group]] file..

chown 可以根据这个命令的第一个参数更改文件所有者和/或文件用户组,例如:

参数 结果
bob 把文件所有者从当前属主更改为用户 bob。
bob:users 把文件所有者改为用户 bob,文件用户组改为用户组 users。
:admins 把文件用户组改为组 admins,文件所有者不变。
bob: 文件所有者改为用户 bob,文件用户组改为用户 bob 登录系统时所属的用户组。

比方说,我们有两个用户,janet 拥有超级用户访问权限,而 tony 没有。用户 janet 想要从 她的家目录复制一个文件到用户 tony 的家目录。因为用户 janet 想要 tony 能够编辑这个文件, janet 把这个文件的所有者更改为 tony:

[janet@linuxbox ~]$ sudo cp myfile.txt ~tony
Password:
[janet@linuxbox ~]$ sudo ls -l ~tony/myfile.txt
-rw-r--r-- 1 root root 8031 2008-03-20 14:30 /home/tony/myfile.txt 
[janet@linuxbox ~]$ sudo chown tony: ~tony/myfile.txt 
[janet@linuxbox ~]$ sudo ls -l ~tony/myfile.txt
-rw-r--r-- 1 tony tony 8031 2008-03-20 14:30 /home/tony/myfile.txt

7.使用指令

type——显示命令的类型

type 命令是 shell 内部命令,它会显示命令的类别,给出一个特定的命令名(做为参数)。

type command

例如:

 ~/Downloads/demo2 (master*) [02:00:44]
lilhoe$ type type   
type is a shell builtin
 ~/Downloads/demo2 (master*) [02:03:38]
lilhoe$ type ls  
ls is an alias for ls -G
 ~/Downloads/demo2 (master*) [02:07:08]
lilhoe$ type cp
cp is /bin/cp
which——显示一个可执行程序的位置

有时候在一个操作系统中,不只安装了可执行程序的一个版本。虽然在桌面系统中这并不普遍,
但在大型服务器中却很平常。为了确定所给定的执行程序的准确位置,使用 which 命令:

 ~/Downloads/demo2 (master*) [02:07:34]
lilhoe$ which ls          
ls: aliased to ls -G
 ~/Downloads/demo2 (master*) [02:08:51]
lilhoe$ which cp
/bin/cp

这个命令只对可执行程序有效,不包括内建命令和命令别名,别名是真正的可执行程序的替 代物。当我们试着使用 shell 内建命令时,我们或者得不到回应,或者是个错误信息:

 ~/Downloads/demo2 (master*) [02:10:31]
lilhoe$ which cd
cd: shell built-in command
xdg-open(opens a file or URL in the user’s preferred application)

在linux中,通常用命令行打开文本文件,比如用命令gedit、more、cat、vim、less。但当需要打开其他格式文件时,比如pdf、jpg、mp3格式文件,咱们通常做法是进入到文件所在的目录,双击打开,很影响效率。事实上,可以通过命令xdg-open打开这些格式文件,甚至是网页,可以像打开文件一样简单。 (mac用户直接使用open即可

xdg-open {
    
     file | URL } 
xdg-open {
    
     --help | --manual | --version } 

$ xdg-open bonita.mp3 
$ xdg-open http://baidu.com 
info——显示程序 Info 条目

作为一个命令程序手册页的替代物,info 内容可通过 info 阅读器程序读取。info 页是超级链接形式的,和网页很相似。info 程序读取 info 文件,info 文件是树型结构,分化为各个结点,每一个包含一个题目。 info 文件包含超级链接,它可以让你从一个结点跳到另一个结点。一个超级链接可通过它开头的星号来辨别出来,把光标放在它上面并按下 enter 键,就可以激活它。

例如:

info ls

在这里插入图片描述

tee——从 Stdin 读取数据,并同时输出到 Stdout 和文件

tee程序从标准输入读入数据,并且同时复制数据到标准输出(允许数据继续随着管道线流动)和一个或多个文件。当在某个中间处理阶段来捕捉一个管道线的内容时,这很有帮助。

➜  Downloads  ls /usr/bin | tee ls.txt | grep zip
bunzip2
bzip2
bzip2recover
funzip
gunzip
gzip
unzip
unzipsfx
zip
zipcloak
zipdetails
zipdetails5.18
zipdetails5.28
zipgrep
zipinfo
zipnote
zipsplit
wc ——打印行数、字数和字节数

-l 选项限制命令输出只能报道行数。添加 wc 到管道线来统计数据,是个很便利的方法。

➜  Downloads  wc paper.tex 
       5       5     122 paper.tex
➜  Downloads  wc -l paper.tex
       5 paper.tex
grep命令用于搜索给定文件,选出符合模式的行。

NAME
     grep, egrep, fgrep, zgrep, zegrep, zfgrep -- file pattern searcher

SYNOPSIS
     grep [-abcdDEFGHhIiJLlmnOopqRSsUVvwxZ] [-A num] [-B num] [-C[num]]
          [-e pattern] [-f file] [--binary-files=value] [--color[=when]]
          [--colour[=when]] [--context[=num]] [--label] [--line-buffered]
          [--null] [pattern] [file ...]

举例:这里创建了一个文本文件test.txt,向里面输入两行文本,查找内容,符合匹配的会输出,$?(将在下一节讲到)返回上一条指令的返回值,0为成功,1为错误。

lilhoe@LilHoedeMacBook-Pro Downloads % touch test.txt
lilhoe@LilHoedeMacBook-Pro Downloads % echo "Hello" > test.txt
lilhoe@LilHoedeMacBook-Pro Downloads % echo "Hello,World" >> test.txt
lilhoe@LilHoedeMacBook-Pro Downloads % grep Hello test.txt
Hello
Hello,World
lilhoe@LilHoedeMacBook-Pro Downloads % echo $?
0
lilhoe@LilHoedeMacBook-Pro Downloads % grep what test.txt
lilhoe@LilHoedeMacBook-Pro Downloads % echo $?
1


课后练习

  1. 用 touch 在 Downloads 文件夹中新建一个叫 semester 的文件。
    首先查看touch的作用:
man touch

NAME
     touch -- change file access and modification times

SYNOPSIS
     touch [-A [-][[hh]mm]SS] [-acfhm] [-r file] [-t [[CC]YY]MMDDhhmm[.SS]]
           file ...

新建:

lilhoe@LilHoedeMacBook-Pro Downloads % touch semester
  1. 将以下内容一行一行地写入 semester 文件:
 #!/bin/sh
 curl --head --silent https://missing.csail.mit.edu

第一行可能有点棘手, # 在Bash中表示注释,而 ! 即使被双引号(")包裹也具有特殊的含义。 单引号(’)则不一样,此处利用这一点解决输入问题。更多信息请参考 Bash quoting手册

echo \#'!'/bin/sh > semester
echo curl --head --silent https://missing.csail.mit.edu >> semester

在这里插入图片描述

  1. 尝试执行这个文件。例如,将该脚本的路径(./semester)输入到您的shell中并回车。如果程序无法执行,请使用 ls命令来获取信息并理解其不能执行的原因。
lilhoe@LilHoedeMacBook-Pro Downloads % ./semester
zsh: permission denied: ./semester

权限不够
执行ls -l命令
显示-rw-r–r-- …显然没有可执行x权限

  1. 使用 chmod 命令改变权限,使 ./semester 能够成功执行,不要使用sh semester来执行该程序。您的shell是如何知晓这个文件需要使用sh来解析呢?更多信息请参考:shebang

首先man chmod查看chmod的作用:

NAME
     chmod -- change file modes or Access Control Lists

SYNOPSIS
     chmod [-fv] [-R [-H | -L | -P]] mode file ...
     chmod [-fv] [-R [-H | -L | -P]] [-a | +a | =a] ACE file ...
     chmod [-fhv] [-R [-H | -L | -P]] [-E] file ...
     chmod [-fhv] [-R [-H | -L | -P]] [-C] file ...
     chmod [-fhv] [-R [-H | -L | -P]] [-N] file ...
chmod ugo+x semester
./semester

HTTP/2 200 
content-type: text/html; charset=utf-8
server: GitHub.com
last-modified: Thu, 20 Aug 2020 00:59:16 GMT
etag: "5f3dcae4-1e33"
access-control-allow-origin: *
expires: Wed, 26 Aug 2020 08:17:55 GMT
cache-control: max-age=600
x-proxy-cache: MISS
x-github-request-id: E3CC:587C:5DC7FC:62F3C9:5F46185A
accept-ranges: bytes
date: Thu, 27 Aug 2020 04:13:11 GMT
via: 1.1 varnish
age: 92
x-served-by: cache-sin18045-SIN
x-cache: HIT
x-cache-hits: 1
x-timer: S1598501592.916027,VS0,VE1
vary: Accept-Encoding
x-fastly-request-id: c3fcfd61f3b4140beb3ad9151db8219e196a26a0
content-length: 7731
  1. 使用 | 和 > ,将 semester 文件输出的最后更改日期信息,写入根目录下的 last-modified.txt 的文件中
touch last_modified.txt
./semester | grep -i "last-modified" > ./last_modified.txt

在这里插入图片描述

  1. 写一段命令来从 /sys 中获取笔记本的电量信息,或者台式机CPU的温度。注意:macOS并没有sysfs,所以mac用户可以跳过这一题。
cat /sys/class/power_supply/battery/capacity

参考:
https://blog.csdn.net/weixin_34032827/article/details/85998637
https://blog.csdn.net/Ke_vin_Xue/article/details/107414410
https://www.jianshu.com/p/3a5fd088ab77
(《The Linux Command Line》[Fifth Internet Edition] William Shotts)

猜你喜欢

转载自blog.csdn.net/m0_45338067/article/details/108248969
今日推荐