Linux专栏主要系统介绍了在Linux的开发和应用过程中所需要的各种基础知识和相关命令,共分为七部分。
1. Linux | 系统状态查看 / 文本文件处理命令_菜鸟的人工智能之路的博客-CSDN博客
2. Linux | 正则表达式和相关概念_菜鸟的人工智能之路的博客-CSDN博客
3. Linux | 文件比较 / vi编辑与使用 / 文件通配符_菜鸟的人工智能之路的博客-CSDN博客
4. Linux | 文件管理 / 目录管理_菜鸟的人工智能之路的博客-CSDN博客
5. Linux | 命令风格 / 文件系统_菜鸟的人工智能之路的博客-CSDN博客
文章目录
1 文件和目录的权限
1.1 文件的权限
用于控制进程对系统的文件和目录的访问
权限的三个级别
- 文件主,同组用户,其他用户
- 每个文件有唯一的属主
普通文件的权限
- 读、写、可执行
- 不可写的文件也可能会被删除
两类可执行文件
程序文件(可执行文件)
- 二进制的CPU指令集合,满足操作系统规定的格式才可以被加载运行。
脚本文件
- 里面存储文本文件。
- 默认的解释程序为/bin/sh。
- 可以在文件的第一行自行指定解释程序(必须是第一行,#! 必须是这个文件首先出现的两个字符)。例如:#! /bin/bash 说明该脚本利用bash进行解释;#! /usr/bin/bc。
- 解释程序也可以是用户自己编写的应用程序。
- 脚本程序运行时,实际上是由解释程序创建一个进程。
1.2 目录的读写权限
(1)目录读写执行权限
读权限
- 如果目录无读权限,那么“目录表”文件不允许读,ls会失败。
写权限
- 若无写权限,那么“目录表”许写。
- 创建文件,删除文件,文件改名会修改目录文件。
- 修改文件不需要修改目录文件,需要修改i节点。
- 目录无写权限不是指目录下所有文件禁止写(目录没有写的权限和目录下的文件的权限没有直接关系)。
执行权限
- 有执行权限意味着分析路径名过程中可检索该目录。
- cat /a/b/c 要求/a,a/b三目录均有x权限,c文件有读权限;否则,命令执行失败。
- cd ../st8 要求当前目录,..和st8必须有x权限。
(2)权限验证的顺序
- 每个文件都有文件主和组的属性(文件节点中)
- 每个进程也有进程主和组的属性(进程PCB中)
这4个属性都是整数,uid和gid的编号与名字对应关系见 /etc下passwd和group文件。需要注意的是超级root用户不会收到权限的制约。
1)文件主与进程主相同
- 使用文件主权限;不再查组和其他用户的权限。
2)文件主与进程主不同,但文件主与进程主同组
- 只使用组权限,不使用关于其他用户的权限。
3)文件主与进程主不同,文件主与进程主又不同组
- 使用文件关于其他用户的权限。
1.3 权限相关命令
确定文件的权限
(1)使用 ls 命令
有关选项 -l 和 -d
- 例如:ls -l 可以查看当前目录下所有文件和子目录的权限
- ls -ld . 列出当前目录自身的权限
(2)chmod 修改权限
1)字母形式
chmod [ugoa] [+-=][rwxst] 文件名表
- u--user 文件主的权限
- g--group 同组其他用户的权限
- o--other 其他用户权限
- a--all 所有上述三级权限
例如:chmod go-rwx *.[ch] 对于所有的.c或者.h文件,对于同组和其他用户都不允许读、写和执行。
chmod a+x batch 对于batch文件,对于所有用户均允许执行。
2)数字形式(八进制数字)
例如:chmod 644 xyz1 xyz2
八进制 | 6 | 4 | 4 |
二进制 | 110 | 100 | 100 |
权限 | rw- | r-- | r-- |
注意:只允许文件主和超级用户修改文件权限。
(3)umask 控制文件/目录的初始权限
功能:决定文件/目录的初始权限
- 用vi新建文件
- 用输出重定向创建文件
- 创建新目录
umask是进程属性的一部分
- umask是shell内部命令
- umask是进程属性的一部分
命令
- umask 打印当前的umask值
- umask 022 将umask值设置为八进制的022
掩码值的含义
- umaxk 022 (000 010 010) //取消新文件和新目录的组w权限和其他用户w权限。
- umask 077 //禁止组权限和其他用户权限(unmask对应比特1处的权限被屏蔽掉)。
系统调用umask
初始文件的权限
- 受open的规定值和进程自身属性umask值影响。
- 已存在的文件的权限,不受open/umask的影响。例如:当umask为077时,用C程序fd=open(filename, O_CREAT|O_WRONLY, 0666);open的权限为0666,利用umask屏蔽掉077后实际为0666。
- 这样可以在创建文件的时候指定文件的权限,或者在后续进程处理过程中通过umask()修改权限。
int umask(int mask);
- mask为指定的新umask值,返回值为原先的umask值。
- 读出进程umask属性而不改变它,需调用umask两次。
1.4 SUID权限
(1)三级权限存在的问题
系统中任一用户,要么对文件的全部内容具有访问权,要么不可访问文件。有的情况下,很不方便。
用户Liu的文件list.txt:希望用户Liang只能读取行首为 # 的行和与他有关的行。这样的话利用三级权限会面临困难,具体怎么解决该问题:
(2)策略和机制相分离
文件list.txt的文件主Liu给文件query增加SUID权限
- $ chmod u+s query
- $ ls -l query
- -rws--x--x 1 liu leader 56134 Dec 10 23:07 query
进程的实际UID和有效的UID
- 一般情况下,进程的实际UID和有效的UID相等。有效UID是用来进行权限判断的,实际UID是用于记账和其他操作。
- 打开文件open()时,系统根据进程的有效UID,与文件所有者UID之间的关系和文件的权限进行访问合法性验证。
- 可执行程序具有SUID权限,进程的实际UID和有效UID不再相等。实际UID是当前用户,而有效UID为可执行文件的文件主。
- SUID使得用户可以通过文件主提供的程序,以文件主的权限访问文件,但这种访问依赖文件主提供的程序,进行有限的访问。
例如某个用户有下述文件,但里面有些信息不想让别人访问到,可以做下述处理:
ls -l list.txt //查看文件的权限
-rw------ 1 liu .... //文件只能是所有者自己读写,
//但实际中需要其他用户也可以访问文件中的部分信息
需要写一个程序query处理只能访问一个文件中的部分信息
chmod u+s query //给文件赋予suid权限
2 Shell的基本机制
2.1 shell概述
kernel和shell
- kernel指内核,是操作系统内部资源管理的一些程序。内核里面的程序允许在CPU的特权状态。
- shell指外壳,相对于CPU内核而言shell是应用程序中的一部分(对于CPU而言,编译程序等都是它的应用程序)。
(1)shell种类
- B-shell:/bin/sh. 由Stephen R. Bourne在贝尔实验室开发,值最早别认可的shell,早期UNIX的标准shell。
- C-shell:/bin/sch 由加利福尼亚大学的William N. Joy 在20世纪70年代开发,最初用在BSD2.0。
- K-shell:Korn shell,/bin/ksh 贝尔实验室的David Korn在1986年开发。是B-shell的超集,支持带类型的变量,数组。
- /bin/bash:Bourne Again shell,是linux上的标准shell,兼容 Bourne shell,扩展了B-shell,吸收了C-shell的某些特点。交互式使用时命令行编辑非常方便。
(2)shell功能
- shell 是命令解释器(每读一行处理一行)。
- 文件名替换,命令替换,变量替换。
- 历史替换,别名替换。
- 流程控制的内部命令(内部命令和外部命令)。
(3)shell特点
- 主要用于批处理,执行效率比算法语言低。
- shell编程风格和C语言等算法语言是有区别的。
- shell是面向命令处理的语言,提供的流程控制结构通过对一些内部命令的解释实现。
- 同C语言设计思路一样,shell本身的设计非常精炼,但是它提供了灵活的机制(策略与机制相分离)。
- shell许多灵活的功能,通过shell替换实现。例如:流程控制多需要的条件判断,四则运算,都由shell之外的命令完成。
(4)学习bash的目的
- 交互方式:熟悉shell的替换机制、转义机制,掌握循环等流程控制,可以编写复合命令。
- 非交互方式:编写shell脚本程序,把一系列的操作,编纂成一个脚本文件,批量处理。
需要了解的shell知识
- 重定向与管道。
- 方便交互使用的功能:历史替换与别名替换。
- shell变量。
- shell的变量替换,命令替换,文件名替换。
- 元字符,如:单引号,双引号。
- 流程控制。
- 子程序。
2.2 bash的启动
(1)三种启动方法
- 注册shell:注册shell
- 键入bash命令:交互式shell
- 脚本解释器
(2)自动执行的一批命令
用户偏好
- 当bash作为注册shell被启动时:自动执行用户主目录下的.bash_profile文件中的命令,~/.bash_profile或$HOME/.bash_profile。当bash作为注册shell退出时:自动执行$HOME/.bash_logout
- 当bash作为交互式shell启动时:自动执行$HOME/.bashrc。
- 可以把类似umask之类的文件,应当写在.bash_profile文件中,在每次启动时都会被执行。
系统级(系统均需要执行,执行时机比用户偏好要早)
- 当bash作为注册shell启动时:自动执行/etc/profile文件中的命令。
- 当bash作为交互式shell启动时:自动执行/etc/bash.bashrc。
- 当bash作为注册shell退出时:自动执行/etc/bash.bash.logout。
(3)脚本文件
编辑文件 lsdir(格式为文本文件,文件名不必须为.sh后缀,只是个惯例),具体脚本代码如下所示:
if [ $# = 0] #判断命令行参数个数是否为零
then
dir=.
else
dir=$1 #赋值为命令行第一个参数
fi
#将所有属性是目录的项目打印出来,打印指定目录下的目录树
find $dir -type d -print
echo '------------------'
cd $dir
pwd
(4)脚本文件的执行
新创建子进程,并在子进程中执行脚本
- <1> bash < lsdir 相当于重定向的操作,启动新的bash进程从lsdir文件里面获取数据输入,然后进行逐行解释。无法携带命令行参数。
- <2> bash lsdir
- bash -x lsdir 每执行一行命令,将命令打印出来。可以看到脚本的执行轨迹。
- bash lsdir /usr/lib/gcc
- <3> 给文件设置可执行属性x:chmod u+x lsdir 然后执行 ./lsdir /usr/lib/gcc
上面的三种方法,都需要启动程序/bin/bash,生成新进程。
在当前shell进程中执行脚本
- . lsdir /usr/lib/gcc 命令中.后的空格表示在当前的shell中执行lsdir脚本
- source lsdir /usr/lib/gcc 意思同上,但是可读性好点
2.3 历史与别名
(1)历史表和历史替换
历史表大小
- 先前键入的命令存在于历史表,编号递增,FIFO刷新。
- 表的大小有变量HISTSIZE设定。
- 修改HISTSIZE的配置应该放入 ~/.bashrc (该文件是系统启动时自动执行)
查看历史表
- 使用内部命令hisroty。(文件$HOME/.bash_history中存储历史表)
历史替换
1)人机交互时直接使用上下箭头键,调出曾经使用过的命令。
2)其他引用历史机制的方法。
- !! 引用上一命令
- !str 以str开头的最近用过的命令,如 !v !m !.
(2)别名和别名替换
在别名表中增加一个别名(内部命令alias),如果需要,应把alias命令放入 .bashrc 中。
alias h="history"
alias p='ping 202.123.23.124'
alias rm='rm -i' #命令重载
alias dir="ls -flad"
(3)TAB键补全
使用TAB键可以补全后续单词,同时可以使用上下键进行滚动选择。
1)补全每行的首个单词
- TAB键补全搜索$PATH下的命令
2)补全行中的其他单词
2.4 输入重定向
输入重定向,指从数据文件中获取stdin。
(1)<filename
从文件filename中获取stdin,例如:sort < telno.txt #表示从文件中获取排序数据,不再通过交互式输入获取。
(2)<<word
从shell脚本文件获取数据直到再次遇到定界符word。换言之就是遇到word之后停止。
定界符所界定内容加工处理(等同双引号处理):
- 变量替换,命令替换
- 不执行文件名生成
从shell脚本程序获取数据直到再次遇到定界符,定界符两侧加单引号:不允许定界符之间的内容进行替换操作。
(3)<<<word
base64 <<< nohavepasswd #将后面的字符变为base64编码格式,也就是<<<后面的所有信息作为命令的输入。
base64 <<< 'no have passwd'
Now : `date`
My Home Dir is $HOME
#执行替换和运行的结果为
Now : Tue Dec 4 12:32 CTS 2020
My Home Dir is /home/li
2.5 输出重定向和管道
(1)程序的标准输入/输出
fd是对应的文件描述符,stdin是标准输入,stdout是标准输出。
使用系统调用(原始I/O)的程序实例
//使用原始I/O方式
int main(void) {
static char *str1 = "string1\n";
static char *str2 = "string2\n";
for (int i = 0; i < 10; i++) {
write(1, str1, strlen(str1));
write(2, str2, strlen(str2));
}
}
使用C语言里面库函数(缓冲I/O)的程序实例
//FIFE类型的变量stdin, stdout, stderr
//使用缓冲I/O
int main(void) {
static char *str1 = "string1\n";
static char *str2 = "string2\n";
for (int i = 0; i < 10; i++) {
printf("%s", str1); //或 fprintf(stdout, "%s", str1);
fprintf(stderr, "%s", str2);
}
}
(2)stdout输出重定向
>filename
将stdout重定向到文件filename,文件已存在则先清空(覆盖方式清空)。
>>filename
将stdout重定向追加到文件filename尾部。
(3)stderr输出重定向
2> filename
将文件句柄2重定向到文件filename。(将错误输出信息也从定向到文件中)
分离stdout与stderr的意义:正常情况一般是重定向到一个文件当中,使用stdout就行,但是有时候可能在重定向的过程中出现错误,这时候需要将错误信息打印出来以方便程序员查看。
2>&1
将文件句柄2重定向到文件描述符1指定的文件。也就是将stdout和stderr重定向合并。
允许对除0,1,2外其他文件句柄输入或输出重定向,例如:
- ./myap 5< a.txt 6> b.dat //在myap程序运行过程中,5号文件不用打开,直接从a.txt中读取;6号文件输出到b.dat文件中。
- gcc try.c > try.err 2>&1 //将标准输出以及标准错误输出都重定向到文件try.err中。
#使用原始I/O方式。文件名为stda
int main(void) {
static char *str1 = "string1\n";
static char *str2 = "string2\n";
for (int i = 0; i < 10; i++) {
write(1, str1, strlen(str1));
write(2, str2, strlen(str2));
}
}
#对于该程序直接执行 ./stda 会输出标准输出和标准错误输出
#使用重定向可以仅仅打印出标准错误输出,将标准输出定向到文件中
./stda > stda.out
#同时将标准错误信息定向到文件stda.err
./stda > stda.out 2> stda.err
./stda > rpt 2>&1
刚开始1和2号文件指向终端,0号文件指向键盘;第一个 > 操作之后,将1号文件的指向变为rpt;后面的2>&!标志2号文件的指向和1号文件一样,都是rpt。
(4)管道
管道只是把标准输出重定向到后面的命令输入中,对于标准错误输出没有进行重定向。如果需要将标准错误输出(2号文件)也定向都后面,需要增加 2>&1。
- gcc try.c 2>&1 | more #more作用是当输出的错误信息满一屏之后就停止,但是如果没有 2>&1 的话,只是保证标准输出信息受more的控制,对于标准错误输出信息不受more控制。