笔记目录
前言
Shell ; Linux ; C语言中文网 ; 笔记
一、什么是Shell
1. 本质 : Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核
//文件操作、输入输出、进程管理等都得依赖内核
2. 运行一个命令,大部分情况下 Shell 都会去调用内核暴露出来的接口, 接口其实就是一个一个的函数,使用内核就是调用这些函数
3. 特殊性 : 开机立刻启动, 调用接口过程对用户透明
查看Shell脚本:
Desktop目录下 :
$ cat /etc/shells
二、进入Shell的两种方式
1.进入Linux控制台
进入控制台后无法截图
- ctrl + alt + F3 // 进入控制台
- ctrl + alt + F2 // 返回图形化操作界面
2.使用终端(Terminal)
三、Shell命令的基本格式
command [选项] [参数]
- 短格式选项 : 用一个减号 - 和一个字母表示,例如ls -l // 通常都为长格式选项的缩写
- 长格式选项 : 用两个减号 -- 和一个单词表示,例如ls --all
1.选项和参数一起使用
-n是 echo 命令的选项,"http://c.biancheng.net/shell/"是 echo 命令的参数,它们被同时用于 echo 命令。
echo 命令用来输出一个字符串,默认输出完成后会换行;给它增加-n选项,就不会换行了。
[mozhiyan@localhost ~]$ echo "http://c.biancheng.net/shell/"
http://c.biancheng.net/shell/
[mozhiyan@localhost ~]$ echo -n "http://c.biancheng.net/shell/"
http://c.biancheng.net/shell/[mozhiyan@localhost ~]$
2.选项附带的参数
-n选项表示读取固定长度的字符串,那么它后面必然要跟一个数字用来指明长度,否则选项不完整
read str // 取用户输入的数据,并把读取到的数据赋值给变量_str
read -n 1 sex // 1是-n选项的参数,sex是 read 命令的参数; 读取一个字符赋值给变量_sex
四、Shell命令的本质
1.内置命令
Shell 内部可以通过函数来实现,当 Shell 启动后,
这些命令所对应的代码(函数体代码)也被加载到内存中,所以使用内置命令是非常快速的。
内置命令不宜过多,过多的内置命令会导致 Shell 程序本身体积膨胀,运行 Shell 程序后就会占用更多的内存。
Shell 是一个常驻内存的程序,占用过多内存会影响其它的程序。
// 只有那些最常用的命令才有理由成为内置命令,比如 cd、kill、echo 等;
2.外部命令
外部的应用程序,一个命令就对应一个应用程序。运行外部命令要开启一个新的进程,所以效率上比内置命令差很多
应用程序就是一个文件,只不过这个文件是可以执行的。既然是文件,那么它就有一个名字,并且存放在文件系统中。
用户在 Shell 中输入一个外部命令后,只是将可执行文件的名字告诉了 Shell,
Shell 在启动文件中增加了一个叫做 PATH 的环境变量,该变量就保存了 Shell 对外部命令的查找路径,
如果在这些路径下找不到同名的文件,Shell 也不会再去其它路径下查找了,它就直接报错。
3.Shell命令执行过程
用户输入一个命令后,Shell 先检测该命令是不是内置命令,如果是就执行
如果不是就检测有没有对应的外部程序, 有的话就转而执行外部程序,执行结束后再回到 Shell
没有的话就报错,告诉用户该命令不存在
不同的路径之间以:分隔。你看,Shell 只会在几个固定的路径中查找外部命令。
如果我们自己用C语言或者 C++ 编写一个应用程序,并将它放到这几个目录下面,那么我们的程序也会成为 Shell 命令。当然,你也可以修改 PATH 变量给它增加另外的路径
//计算从 m 累加到 n 的和
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int start = 0;
int end = 0;
int sum = 0;
int opt;
char *optstring = ":s:e:";
while((opt = getopt(argc, argv, optstring))!= -1){
switch(opt){
case 's': start = atoi(optarg); break;
case 'e': end = atoi(optarg); break;
case ':': puts("Missing parameter"); exit(1);
}
}
if(start<0 || end<=start){
puts("Parameter error"); exit(2);
}
for(int i=start; i<=end; i++){
sum+=i;
}
printf("%d\n", sum);
return 0;
}
[mozhiyan@localhost ~]$ getsum -s 1 -e 100
5050
五、Shell命令的选项和参数的本质
选项和参数, 有的传递给了函数(内置命令),有的传递给了应用程序(外部命令)
这些数据是由空格分隔的,它们被分隔成了几份,就会转换成几个参数。
例如 : getsum -s 1 -e 100要向函数传递四个参数,read -n 1 sex要向函数中传递三个参数。
命令后面附带的数据都是“原封不动”地传递给了函数,
比如getsum -s 1 -e 100要传递的四个参数分别是 -s、1、-e、100,减号-也会一起传递过去,
在函数内部,减号-可以用来区分该参数是否是命令的选项。
/*
函数内部解析参数
第 11~20 行是解析参数的关键代码,
getopt.h 头文件中的 getopt() 函数是值得重点研究的,有了该函数我们就不用自己去解析参数了
第 27~32 行将接收到的参数打印出来,以便读者更好地观察。
*/
#include <stdio.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
int main(int argc, char *argv[]){
int start = 0;
int end = 0;
int sum = 0;
int opt;
char *optstring = ":s:e:";
//分析接收到的参数
while((opt = getopt(argc, argv, optstring))!= -1){
switch(opt){
case 's': start = atoi(optarg); break;
case 'e': end = atoi(optarg); break;
case ':': puts("Missing parameter"); exit(1);
}
}
//检测参数是否有效
if(start<0 || end<=start){
puts("Parameter error"); exit(2);
}
//打印接收到的参数
printf("Received parameters: ");
for(int i=0; i<argc; i++){
printf("%s ", argv[i]);
}
printf("\n");
//计算累加的和
for(int i=start; i<=end; i++){
sum+=i;
}
printf("sum=%d\n", sum);
return 0;
}
六、Shell命令提示符
CentOS 中,默认的提示符类似下面这样:
[mozhiyan@localhost ~]$
各个部分的含义如下:
- []是, 提示符的分隔符号,没有特殊含义。
- mozhiyan表示, 当前登录的用户,我现在使用的是 mozhiyan 用户登录。
- @是, 分隔符号,没有特殊含义。
- localhost表示, 当前系统的简写主机名(完整主机名是 localhost.localdomain)。
- ~代表, 用户当前所在的目录为主目录(home 目录)。如果用户当前位于主目录下的 bin 目录中,那么这里显示的就是bin。
- KaTeX parse error: Expected 'EOF', got '#' at position 55: …(root 用户),提示符就是#̲;如果是普通用户,提示符就是。
1.主目录
Linux 系统是纯字符界面,用户登录后,要有一个初始登录的位置,这个初始登录位置就称为用户的主目录(home 目录)。
超级用户的主目录为/root/,普通用户的主目录为/home/用户名/。
有的资料也称为“家目录”,“家”是 home 的直译,它们都是一个意思。
用户在自己的主目录中拥有完整权限,所以我们也建议操作实验可以放在主目录中进行。
我们使用 cd 命令切换一下用户所在目录,看看有什么效果。
[mozhiyan@localhost ~]$ cd demo
[mozhiyan@localhost demo]$ cd /usr/local
[mozhiyan@localhost local]$
仔细看,如果切换用户所在目录,那么命令提示符中会变成用户当前所在目录的最后一个目录
(不显示完整的所在目录 /usr/ local/,只显示最后一个目录 local)。
2.第二层命令提示符
有些命令不能在一行内输入完成,需要换行,这个时候就会看到第二层命令提示符。第二层命令提示符默认为>
[mozhiyan@localhost ~]$ echo "Shell教程"
Shell教程
[mozhiyan@localhost ~]$ echo "
> http://
> c.biancheng.net
> "
http://
c.biancheng.net
第一个 echo 命令在一行内输入完成,不会出现第二层提示符。第二个 echo 命令需要多行才能输入完成,提示符>用来告诉用户命令还没输入完成,请继续输入。
echo 命令用来输出一个字符串。字符串是一组由" "包围起来的字符序列,echo 将第一个"作为字符串的开端,将第二个"作为字符串的结尾。对于第二个 echo 命令,我们将字符串分成多行,echo 遇到第一个"认为是不完整的字符串,所以会继续等待用户输入,直到遇见第二个"。
七、Shell修改命令提示符
- PS1 控制最外层的命令提示符格式。
- PS2 控制第二层的命令提示符格式。
以下方式修改的命令提示符只在当前的 Shell 会话期间有效,
希望持久性地修改 PS1,就得把 PS1 变量的修改写入到 Shell 启动文件中
suagr@ubuntu:~/Desktop$ PS1="[\t][\u]\$ " // 修改后可以显示当前的时间和用户名
PS1="[c.biancheng.net]\$ " // 第二次修改后显示指定字符串
八、第一个Shell脚本
#!/bin/bash
echo "What is your name?"
read PERSON
echo "Hello, $PERSON" # 变量名前边要加上$,否则变量名会作为字符串的一部分处理
九、执行Shell脚本
查看当前进程 PID :
suagr@ubuntu:~/Desktop$ echo $$
7740
1.在新进程中运行 Shell 脚本
(1).将 Shell 脚本作为程序运行
Shell 脚本也是一种解释执行的程序,可以在终端直接调用(需要使用 chmod 命令给 Shell 脚本加上执行权限)_./test.sh
suagr@ubuntu:~/Desktop$ chmod +777 ./test.sh ##切换到 test.sh 所在的目录, 给脚本添加执行权限
suagr@ubuntu:~/Desktop$ ./test.sh #执行脚本文件
What is your name?
world
Hello, world #运行结果
suagr@ubuntu:~/Desktop$
(2).将 Shell 脚本作为参数传递给 Bash 解释器
直接运行 Bash 解释器,将脚本文件的名字作为参数传递给 Bash_/bin/bash test.sh
suagr@ubuntu:~/Desktop$ /bin/bash test.sh
What is your name?
world
Hello, world
suagr@ubuntu:~/Desktop$
2.在当前进程中运行 Shell 脚本
source 命令 :
source 是 Shell 内置命令的一种,它会读取脚本文件中的代码,并依次执行所有语句。
可以理解为,source 命令会强制执行脚本文件中的全部命令,而忽略脚本文件的权限。
用法 : source filename ; 简写为:. filename
suagr@ubuntu:~/Desktop$ . ./test.sh
What is your name?
world
Hello, world
suagr@ubuntu:~/Desktop$ source ./test.sh
What is your name?
world
Hello, world
十、四种Shell运行方式
- 登录式 与 非登录式 :
直接使用 Shell_ 非登录式,
输入用户名和密码后再使用 Shell_ 登录式
- 交互式 与 非交互式 :
在 Shell 中一个个地输入命令并及时查看它们的输出结果,整个过程都在跟 Shell 不停地互动_ 交互式
运行一个 Shell 脚本文件,让所有命令批量化、一次性地执行_ 非交互式
- 四种Shell运行方式 :
1. 交互式的登录 Shell
2. 交互式的非登录 Shell
3. 非交互式的登录 Shell
4. 非交互式的非登录 Shell
1.判断Shell是否为交互式
suagr@ubuntu:~/Desktop$ echo $-
himBHs
2.判断 Shell 是否为登录式
十一、Shell配置 文件/脚本 的加载
十二、编写自己的Shell配置 文件/脚本
总结
23/06/26 - 未完结