一,shell编程的概念
1.0Shell与内核的关系
内核是Linux系统的核心,它是操作系统的最底层部分,负责管理计算机的硬件资源,例如CPU、内存、磁盘等。内核还提供了许多系统调用,供应用程序使用,例如打开文件、读写文件、创建进程、网络通信等等。
由于用户无法直接操作内核,所以需要借助Shell来进行命令的传输:
Shell是Linux系统中的一个用户界面,它是用户与内核之间的一个接口。Shell提供了一个命令行界面和一个脚本语言,用户可以使用各种命令和脚本来与操作系统交互。Shell解释器接受用户输入的命令,将其解析为系统调用和其他操作,并将它们传递给内核执行。
在Linux中,Shell与内核之间的交互主要通过系统调用来实现。当用户在Shell中输入一个命令时,Shell解释器将命令解析为系统调用和其他操作,并将它们传递给内核执行。当内核执行完命令后,将结果返回给Shell解释器,Shell解释器将结果显示给用户。
另外,Shell还可以通过环境变量来影响内核的行为。例如,PATH环境变量指定了可执行文件的搜索路径;HOME环境变量指定了当前用户的主目录;LD_LIBRARY_PATH环境变量指定了动态链接库的搜索路径等等。这些环境变量可以影响系统调用的执行结果。
总之,Shell和内核是Linux系统中两个非常重要的概念,它们之间的关系非常密切。Shell作为用户与内核之间的接口,负责解析用户输入的命令,并将其转换为系统调用和其他操作,从而影响内核的行为。
1.1Shell与Shell脚本
1.1.1Shell
Shell是一种命令行解释器,用来解释执行用户的命令,它是操作系统内核和用户之间的接口。一般是用户一条条输入,Shell一条条执行,这种方式称为交互式。它接收用户的命令,并将其转化为内核可以理解的指令,同时将内核的输出返回给用户。
1.1.2Shell脚本
Shell还有一种执行命令的方式就是批处理(Batch),用户实现写好一个Shell脚本(Script),里面包含很多条命令,Shell一次性执行完所有命令,不用一条条输入执行。Shell脚本是一种用于自动化任务和管理系统的脚本语言。它们是在Shell中编写的一系列命令和控制结构,以执行特定的任务。Shell脚本可以通过命令行运行,并可以接受用户输入和参数。
因此,Shell是一种交互式的命令行解释器,而Shell脚本是一种脚本语言,用于编写自动化任务和管理系统。Shell脚本通常包含一系列Shell命令和控制结构,可以在Shell中运行。
1.2Shell脚本与编程语言的区别
Shell脚本是一种脚本语言,用于编写自动化任务和管理系统。它们通常用于在Linux和其他Unix系统上编写脚本,以执行诸如文件操作、系统管理、网络编程等任务。
编程语言是一种通用的编程语言,可以用于编写广泛的应用程序。它们可以用于开发Web应用程序、桌面应用程序、移动应用程序、游戏等各种应用程序。
Shell脚本是一种解释性语言,与编译性语言(如C、Java等)不同。解释器读取脚本并将其转换为机器指令,而编译器将源代码转换为机器指令。
Shell脚本通常使用命令行界面(CLI)与用户交互,而编程语言可以使用GUI界面或CLI与用户交互。
Shell脚本通常使用一些基本的控制结构,例如条件语句和循环语句,而编程语言通常提供更丰富的控制结构和数据类型。
总的来说,Shell脚本是一种特定用途的脚本语言,用于自动化系统管理任务,而编程语言则更通用,可用于编写广泛的应用程序。
二,Shell编程基本语法
2.1系统调用fork 和exec介绍
在Shell编程中,fork和exec是两个重要的系统调用,常用于创建新的进程和执行新的程序。
2.1.1fork
fork是一个系统调用,用于创建一个新的进程。调用fork时,操作系统会在当前进程的地址空间中创建一个完全相同的子进程,包括所有变量和指令。子进程是父进程的副本,它从父进程继承了所有的资源和状态,并获得了自己的进程ID。父进程和子进程共享文件描述符,但它们各自拥有独立的地址空间。
fork()函数的语法如下:
pid_t pid = fork();
if (pid == 0) {
// 子进程
} else if (pid > 0) {
// 父进程
} else {
// fork失败
}
2.1.2exec
exec是一个系统调用,用于执行一个新的程序。调用exec时,操作系统会将当前进程的地址空间替换为新的程序的地址空间,并开始执行新程序的指令。exec函数有多个变体(如execl、execv、execle等),它们之间的差异在于参数的传递方式和路径的表示方式等。
exec()函数的语法如下:
int execvp(const char *file, char *const argv[]);
其中,file参数指定要执行的程序的文件名,argv参数是一个包含命令行参数的字符串数组。exec函数将通过file参数指定的程序替换当前进程,并将argv参数传递给新程序。
一般情况下,fork和exec会组合在一起使用,以创建一个新的进程并执行新的程序。
下面是一个示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
if (pid == 0) {
// 子进程
char *args[] = {"ls", "-l", NULL};
execvp(args[0], args);
} else if (pid > 0) {
// 父进程
wait(NULL);
printf("Child process finished.\n");
} else {
// fork失败
printf("Fork failed.\n");
return 1;
}
return 0;
}
这个示例代码创建一个新进程,然后执行"ls -l"命令。子进程使用execvp函数来执行新程序,而父进程使用wait函数等待子进程的结束,并打印一条消息以指示子进程已经完成。
2.2Linux中外部命令与内建命令
2.2.1外部命令
外部命令是指由可执行文件或脚本文件组成的命令。这些命令通常是独立的可执行文件,可以在终端中使用绝对路径或相对路径来执行它们。Linux系统提供了许多外部命令,例如**ls、grep、**awk、sed等等。这些命令通常是由操作系统提供的,也可以是由第三方软件提供的。通过环境变量 PATH来设这配置,在执行相应的外部命令的时候系统会向PATH中的地址去寻找相关的支持。
2.2.2 内建命令
内建命令是指由Shell解释器本身提供的命令。这些命令不需要单独的可执行文件或脚本文件,它们直接由Shell解释器处理。Linux系统中的常见内建命令包括cd、echo、export、alias、history等等。由于内建命令不需要启动新进程,因此它们通常比外部命令执行得更快。
在执行命令时,Shell优先查找内建命令,如果找到了就直接执行;如果没有找到,则查找可执行文件或脚本文件,如果找到了则执行。如果既没有找到内建命令,也没有找到可执行文件或脚本文件,则Shell会显示一个错误消息。
可以使用type命令来查看一个命令是内建命令还是外部命令。例如:
$ type cd
cd is a shell builtin
$ type ls
ls is aliased to `ls --color=auto'
ls is /bin/ls
这个示例中,type命令显示cd是一个内建命令,而ls是一个外部命令。注意,ls还有一个别名(alias),它指向/bin/ls可执行文件。
2.3Shell编程的基本语法
注释:用 # 开头的行表示注释,注释可以出现在代码任何位置。
变量:使用变量时,变量名不需要使用 $ 符号,赋值时需要使用 = 符号。
输出:使用 echo 命令可以将指定的文本输出到屏幕上。
输入:使用 read 命令可以从用户处获取输入,并将其存储在变量中。
条件语句:使用 if 语句可以根据指定条件执行不同的命令。
循环语句:使用 for 循环和 while 循环可以多次执行相同的命令。
函数:使用函数可以编写可重用的代码块。
- 注释
# 这是一条注释
- 变量
name="Tom"
- 输出
echo "Hello, world!"
- 输入
read -p "请输入您的名字:" name
echo "您好,$name!"
- 条件语句
if [ $age -gt 18 ]
then
echo "您已经成年了!"
else
echo "您还未成年!"
fi
- 循环语句
for i in {1..10}
do
echo $i
done
while [ $count -lt 10 ]
do
echo $count
count=$((count+1))
done
- 函数
function greet {
echo "Hello, $1!"
}
greet "Tom"