chapter 10:Sh 编程
chapter 10:Sh 编程
摘要
本章主要内容是sh编程,解释了sh脚本和不同版本的sh。它将sh脚本与C程序进行了比较,并指出了解释型语言和编译型语言之间的区别。
10.1 sh脚本
- sh脚本是一个包含sh语句的文本文件,用于执行命令解释器sh的命令
- sh脚本的第一行通常以#!开头,这被称为shebang,指定了脚本所针对的程序名称
- 使用chmod +x命令将脚本文件设为可执行
- sh脚本可以执行各种命令和内置命令,使用echo命令可以在脚本中输出文本
10.2 sh脚本与C程序的比较
- sh脚本和C程序在语法形式和用法上有一些相似之处,但根本上是不同的
sh | C |
---|---|
INTERPRETER: read & execute | COMPILE-LINKED to a.out |
mysh a b c d | a.out a b c d |
main(int argc, char *argv[ ]) |
- sh脚本是解释执行的,逐行读取并执行命令,而C程序需要先编译为二进制可执行文件后再运行
- 在C程序中,变量有类型,而在sh脚本中,一切都是字符串
- C程序需要有一个main()函数作为入口点,而sh脚本的入口点是脚本中的第一个可执行语句
10.3 命令行参数
- sh脚本可以通过命令行参数来调用,参数可以通过
$0
、$1
、$2
等位置参数来访问 - 前10个命令行参数可以直接通过
$0
到$9
的形式访问,其他参数需要使用${10}
到${n}
的形式引用 - 内置变量
$#
和$*
可以用于计算和显示命令行参数的数量和所有参数的值 - 其他与命令执行相关的内置变量有
$$
表示正在执行sh的进程的PID,$?
表示上次命令执行的退出状态
示例:
假设以下mysh脚本按如下方式运行:
mysh abc D E F G H I J K L M N
# 1 2 3 4 5 6 7 8 9 10 11 12
该脚本的内容如下:
1. #! /bin/bash
2. echo \$# = $# # $# = 12
3. echo \$* = $* # $* = abc D E F G H I J K L M N
4. echo $1 $9 $10 # abc K abc0 (注意:$10变成了abc0)
5. echo $1 $9 ${10} # abc K L (注意:${10}是L)
6. shift # replace $1、$2..with $2、$3...
7. echo $1 $9 ${10} # D L M
- 通过实例展示了sh脚本中使用命令行参数的方法
- 特殊字符
$
表示替换,若要原样使用$
,需要使用单引号或通过\
进行转义 - 注意在脚本中处理
$10
时的情况,sh将其视为$1
和0
的连接,并将$1
替换成abc
,导致$10
变成abc0
- 使用
shift
命令可以将位置参数左移一位,使得$2=$1
、$3=$2
,依此类推
10.4 内置变量
Shell具有许多内置变量,例如PATH、HOME、TERM等。用户还可以使用任何符号作为Shell变量,无需声明。所有的Shell变量值都是字符串。未分配值的Shell变量是空字符串。
变量的赋值
Shell变量可以通过以下方式设置或分配值:
变量名=字符串 # 注意:令牌之间不能有空格
如果A是一个变量,则$A是它的值。
echo A ==> A
echo $A # 如果变量A未设置,打印 (null)
A="this is fun" # 设置 A 的值
echo $A ==> this is fun
B=A # 将A分配给B
echo $B ==> A(B被分配了字符串"A")
B=$A # B取A的值
echo $B ==> this is fun
10.5 引号
Shell中有许多特殊字符,如$、/、*、>、<等,为了使用它们作为普通字符,需要使用\或单引号将它们引起来。在单引号内无法使用转义符或变量,但是在双引号内可以使用变量。
A=xyz
echo \$A ==> $A # 转义$字符
echo '$A' ==> $A # 单引号内无法使用转义符或变量
echo "see $A " ==> see xyz # 在双引号内可以使用变量
10.6 语句执行
Shell语句包括所有Unix /Linux命令,具有可能的I/O重定向。此外,Shell编程语言也支持条件测试、循环和case等语句,以控制Shell程序的执行。
ls
ls > outfile
date
cp f1 f2
mkdir newdir
cat < filename
10.7.1 内置命令
sh 有许多内置命令,它们在执行时不会派生出新的进程。以下是一些常用的内置命令:
. file
: 读取并执行文件。break [n]
: 退出最接近的第 n 层嵌套循环。cd [dirname]
: 改变当前目录。continue [n]
: 重新开始最接近的第 n 层嵌套循环。eval [arg …]
: 对参数进行一次求值并让 sh 执行结果命令。exec [arg …]
: 让 sh 执行命令并退出当前进程。exit [n]
: 让 sh 以指定的状态码 n 退出。export [var .. ]
: 导出变量给后续的命令。read [var … ]
: 从标准输入读取一行并将其分割成标记,将标记值赋给列出的变量。set [arg … ]
: 设置执行环境中的变量。shift
: 将位置参数 3 … 重命名为 2 … 。trap [arg] [n]
: 接收到信号 n 时执行 arg 。umask [ddd]
: 设置umask为八进制数字ddd。wait [pid]
: 等待进程 pid ,如果 pid 没有被给定,则等待所有活动子进程。
read 命令:
当 sh 执行 read
命令时,它会等待从标准输入中获取输入行。它将输入行分割成标记,并将这些标记分配给指定变量。一个常见的用法是通过 read
命令来让用户与执行的 sh
进程进行交互。例如:
echo -n "enter yes or no : " # 等待标准输入输入行
read ANS # 读取标准输入中的一行
echo $ANS # 输出用户的输入
在获取到输入之后,sh 可以根据输入字符串来决定下一步该做什么。
10.7.2 Linux 命令
sh 可以执行所有的 Linux 命令。其中,一些命令已经成为了 sh 的常用部分,因为它们在 sh 脚本中被广泛使用。以下列出并解释了其中的一些命令。
echo 命令
echo
命令会将参数字符串作为行输出到标准输出。除非被引用,它通常将连续的空格缩减为一个空格。
示例:
echo This is a line # 输出 This is a line
echo "This is a line" # 输出 This is a line
echo -n hi # 输出 hi,但不换行
echo there # 输出 hi there
expr 命令
由于所有的 sh 变量都是字符串,因此我们无法直接将它们作为数字值更改。例如,下面的语句:
I=123 # I 被赋值为字符串 "123"
I=I + 1 # I 被赋值为字符串 "I + 1"
与其将 I
的数值增加 1,上述语句只是将 I
更改为字符串 "I + 1",这肯定不是我们所希望的(即将 I
更改为 "124")。间接地改变 sh 变量的(数值)值可以通过 expr
命令来完成。expr
是一个程序,它的运行方式如下:
expr string1 OP string2 # OP 为任何二元数字运算符
它首先将两个参数字符串转换为数字,执行(二元)运算符 OP,然后将结果数字转换回字符串。因此,执行下面的操作:
I=123
I=$(expr $I + 1)
将 I
从 "123" 更改为 "124"。同样地,expr
还可用于对 sh 变量执行其他算术运算,其值是由数字 digit
字符串构成的。
管道命令
sh 脚本中经常使用管道来充当过滤器。例如:
ps –ax | grep httpd
cat file | grep word
实用程序命令
除了上述的 Linux 命令,sh 还使用许多其他实用程序程序作为命令。这些工具包括:
awk
: 数据操作程序。cmp
: 比较两个文件。comm
: 选择两个已排序文件中的相同行。grep
: 在一组文件中匹配模式。diff
: 查找两个文件之间的差异。join
: 通过相同键连接记录来比较两个文件。sed
: 流或行编辑器。sort
: 排序或合并文件。tail
: 输出文件的最后 n 行。tr
: 单向字符转换。uniq
: 从文件中删除连续的重复行。
10.8 命令替代
在sh中,使用
示例
```shell echo10.9 sh控制语句
sh是一种编程语言。它支持许多执行控制语句,与C语言类似。
10.9.1 if-else-fi语句
if-else-fi语句的语法为:
if [ condition ]
then
statements
else
statements
fi
- 每个语句必须单独一行,但是如果它们由分号;分隔,那么sh允许在同一行上分隔多个语句。
- sh允许使用-eq,-ne,-lt,-gt等运算符将参数作为整数进行比较。
- TEST程序还可以测试文件类型和文件属性,在文件操作中经常需要。
10.9.2 for语句
sh中的for语句与C中的for循环行为相同。
其语法是:
for VARIABLE in string1 string2 .... stringn
do
commands
done
示例
for FRUIT in apple orange banana cherry
do
echo $FRUIT # 打印apple orange banana cherry每一行
done
for NAME in $*
do
echo $NAME # 列出所有的命令行参数字符串
if [ -f $NAME ]; then
echo $NAME is a file
elif [ -d $NAME ]; then
echo $NAME is a DIR
fi
done
10.9.3 while语句
sh中的while语句与C中的while循环相似。
其语法为:
while [ condition ]
do
commands
done
当条件为true时,sh将重复执行do-done关键字中的命令。
示例
以下代码段创建目录dir0、dir1 ... dir10000:shell
I=0 # 将I设置为 "0" (STRING)
while [ $I != 10000 ] # 作为字符串进行比较;或者作为数字运行while [ $I \< 1000 ]
do
echo $I # echo current $I value
mkdir dir$I # 创建目录dir0、dir1等
I=$(expr $I + 1) # 使用expr将I的值加1
done
10.9.4 until-do语句
sh的until-do语句与C语言中的do-until语句类似。
其语法为:
until [ $ANS = "give up" ]
do
echo -n "enter your answer : "
read ANS
done
sh将重复执行do-done关键字中的命令,直到条件为真为止。
10.9.5 case语句
sh的case语句与C语言中的case语句类似,但在sh编程中很少使用。
其语法为:
case $variable in
pattern1) commands;; # 注意双分号;;
pattern2) command;;
patternN) command;;
esac
10.9.6 continue和break语句
与C语言中一样,continue重启最近循环的下一次迭代,而break退出最近的循环,它们在sh中与C中完全相同。
10.10 I/O重定向
- I/O重定向可以将输入和输出从默认的stdin、stdout、stderr重定向到其他文件。
- 使用" > file"将stdout重定向到文件中,如果文件不存在,则创建该文件。
- 使用" >> file"将stdout追加到文件中。
- 使用" < file"将文件作为stdin输入,文件必须存在且有读取权限。
- 使用" << word"从"here"文件获取输入,直到出现只包含"word"的行。
10.11 嵌入文档
- 嵌入文档允许将stdin的输入输出到stdout,直到遇到预先设定的关键字。
- 可以使用echo和预先设定的关键字来创建Here文档。
- 嵌入文档通常用于生成长的描述性文本块,而无需逐行回显。
10.12 sh函数
- sh函数的定义方式为"func(){ }"。
- 所有函数必须在可执行语句之前定义。
- 函数可以通过"$0"、"
n"来引用传递的参数。 - 函数执行完成后,可以通过"$?"获取其退出状态。
10.13 sh中的通配符
- "*"通配符可以扩展为当前目录中的所有文件。
- "?"通配符用于查询文件名中的字符。
- "[]"通配符用于查询文件名中的一对"[]"中的字符。
10.14 命令分组
- 可以使用"{ }"或"()"将命令分组在一起。
- "{ }"在同一环境中执行命令,并可用于重定向I/O。
- "()"由子进程执行,可以更改工作目录和分配变量,不会影响父进程。
10.15 eval语句
- eval是sh内置命令,用于将输入参数字符串连接为单个字符串。
- eval会执行变量和命令替换,并将生成的字符串作为sh的输入执行。
10.16 调试sh文本
- 使用子 sh 进行调试,子 sh 需要使用 -x 选项进行调试,例如
bash -x mysh
,会显示每个要执行的 sh 命令(包括变量和命令替换)执行命令之前。 - 如果出现错误,sh 将停在错误行并显示错误消息。
10.17 sh 脚本的应用
- sh 脚本最常用于执行包含一长串命令的常规工作。
- 例子 1:Linux 安装包是用 sh 脚本编写的,用户在安装过程中,可以与该 sh 脚本交互,查找硬盘、对硬盘分区和格式化、从安装媒介中提取文件并安装到目录中。
- 例子 2:登录过程会执行一系列的 sh 脚本,如 .login、.profile、.bashrc 等,来自动配置用户进程的执行环境。
- 例子 3:编译链接任务,可以通过包含编译和链接命令的 sh 脚本来完成简单的编译链接任务,而不是使用 Makefiles。
- 例子 4:为 Linux 机器上的 CS 课程创建用户帐户。
苏格拉底挑战
点击查看问答记录
学习Sh编程知识 Shared Chat•Default (GPT-3.5)学习Sh编程知识
September 24, 2023我在学习Sh Programming知识点,请你以苏格拉底的方式对我进行提问,一次一个问题当然,让我们以苏格拉底的方式开始学习Sh(Shell)编程知识。首先,我要问你:
什么是Shell编程,你认为Shell编程的主要目的是什么?
Shell编程是一种计算机编程技术,它主要用于与计算机操作系统的命令行界面交互。Shell编程的主要目的是编写一系列的命令和脚本,以自动化、批处理或执行各种系统任务和操作。非常好的回答!接下来的问题是:
在Shell编程中,你知道有哪些常见的Shell类型?每种Shell类型有什么特点?
1. Bourne Shell (sh):
- 特点:Bourne Shell 是Unix系统中最早的Shell。它具有简单的语法,但功能较为基本。通常作为标准Shell的基础。
- Bash (Bourne Again Shell):
- 特点:Bash是Bourne Shell的增强版本,广泛用于Linux和许多其他Unix系统。它支持更多功能,包括命令历史、命令补全等。
- C Shell (csh):
- 特点:C Shell是另一种Unix Shell,它具有与C编程语言类似的语法。它支持别名和历史命令。
- Korn Shell (ksh):
- 特点:Korn Shell是Unix系统上的强大Shell,结合了Bourne Shell和C Shell的一些特性,具有丰富的功能和编程能力。
- Zsh (Z Shell):
- 特点:Zsh是一种高级Shell,具有强大的自动补全、插件支持和定制选项。它在用户友好性和可扩展性方面表现出色。
你对各种Shell类型的了解很充分,继续前进:
在Shell编程中,什么是变量,以及为什么它们在脚本中如此重要?
在Shell编程中,变量是用来存储和表示数据的符号名称。这些数据可以是数字、文本、文件名、命令输出等等。变量在Shell脚本中非常重要,因为它在脚本中使得存储和操作数据可行,使脚本更加灵活和有用。非常正确!接下来的问题是:
Shell编程中,如何声明和使用变量?有哪些常见的变量类型?
在Shell编程中,声明和使用变量非常简单。你可以使用等号(=)将值赋给变量,并在需要的地方引用该变量的值。要在脚本中使用该变量的值,可以在变量前加上美元符号($): 常见的变量类型包括: 1. 字符串变量:用于存储文本数据。 2. 整数变量:用于存储整数值。 3. 数组变量: 用于存储多个值的有序集合。 4. 环境变量:用于存储系统环境信息和配置。 5. 位置参数变量: 用于存储命令行参数。 6. 特殊变量:shell还提供了一些特殊变量,如 `$?`(上一个命令的退出状态)、`$$`(当前Shell进程的PID)、`$0`(当前脚本的名称)等。你对变量的声明和使用以及常见的变量类型有了清晰的理解。接下来的问题是:
在Shell编程中,你知道如何进行条件测试和控制流程吗?请简要描述一下。
Shell中常用的条件测试和控制流程结构: 1. 条件测试(if语句): `if` 语句用于在满足特定条件时执行一组命令。基本的语法如下: if [ condition ]; then # 在条件满足时执行的命令 fi 2. 条件测试和否则(if-else语句): 如果需要在条件不满足时执行另一组命令,可以使用 `if-else` 结构: if [ condition ]; then # 在条件满足时执行的命令 else # 在条件不满足时执行的命令 fi 3. 多条件测试(elif语句):*如果需要测试多个条件并根据不同条件执行不同的操作,可以使用 `elif`(else if 的缩写): if [ condition1 ]; then # 在条件1满足时执行的命令 elif [ condition2 ]; then # 在条件2满足时执行的命令 else # 在所有条件都不满足时执行的命令 fi 4. 循环结构(for和while循环): Shell还支持 `for` 和 `while` 循环,用于重复执行一组命令,直到某个条件不再满足。这允许你处理列表、文件内容或需要重复处理的任务。你对条件测试和控制流程结构的解释非常清晰。接下来的问题是:
在Shell编程中,如何定义和使用函数?函数有什么作用?
在Shell编程中,你可以定义和使用函数来封装一组命令,使其可重复使用。函数在Shell脚本中具有以下作用: 代码重用: 函数允许你将一组相关的命令封装在一个独立的单元中,以便在脚本的不同部分或在不同脚本中多次使用。这样可以提高代码的可维护性和重用性。 模块化: 通过将代码分解成函数,可以使脚本更具结构化和模块化,使其更易于理解和维护。 简化脚本: 使用函数可以减少主程序部分的复杂性,使主程序更加清晰,易于阅读。非常好的解释!接下来的问题是:
在Shell编程中,你知道如何处理用户输入和命令行参数吗?如果知道,请简要描述一下。
当你在Shell编程中想要处理用户输入和命令行参数时,有一些基本的方法: 1. 获取用户输入(read命令): 可以使用`read`命令来从用户那里获取输入。这通常用于在脚本中与用户进行交互。 2. 处理命令行参数:命令行参数是在运行脚本时通过命令行传递给脚本的值。 3. 获取参数数量和所有参数:可以使用`$#`来获取传递给脚本的参数数量,使用`$@`来获取所有参数的列表。你对处理用户输入和命令行参数的方法有很好的了解。接下来的问题是:
在Shell编程中,你知道如何进行文件操作吗?如果知道,请描述一些常见的文件操作和命令。
当进行Shell编程时,文件操作是一个非常重要的方面,用于处理文件的创建、读取、写入和管理。以下是一些常见命令和操作: 1. 创建文件(touch命令):*`touch`命令用于创建一个新的空文件,或者更新现有文件的时间戳。 2. 复制文件(cp命令):`cp`命令用于复制文件。你需要指定源文件和目标文件的路径。 3. 移动/重命名文件(mv命令):`mv`命令用于移动文件到新的位置或者重命名文件。 4. 删除文件(rm命令):`rm`命令用于删除文件。 5. 查看文件内容(cat和more命令):`cat`命令用于显示文件的全部内容,而`more`命令允许你逐页查看文件。 6. 文件编辑器(nano、vim和emacs等):你可以使用文本编辑器如`nano`、`vim`或`emacs`来编辑文件的内容。 7. 文件权限和所有权(chmod和chown命令):`chmod`命令用于更改文件的权限,`chown`命令用于更改文件的所有者。 8. 查找文件(find命令):`find`命令用于在指定目录下查找文件。 9. 文件排序和筛选(sort和grep命令):*`sort`命令用于对文件内容进行排序,而`grep`命令用于查找.;.针对我Sh Programming知识点,我理解了吗?你对Shell编程中的文件操作有很好的了解。接下来的问题是:
在Shell编程中,你知道如何使用条件测试来检查文件和目录的存在吗?如果知道,请描述一些相关的命令和方法。
针对我Sh Programming知识点,我理解了吗?是的,你对Shell编程(Sh Programming)的知识点有了很好的理解。你已经了解了Shell编程的基本概念、条件测试、控制流程、变量、函数、文件操作等重要方面。如果你有任何进一步的问题或需要更深入的了解,请随时提出。
我的回答结束了,请对我的回答进行评价总结你在回答关于Shell编程知识点的一系列问题时表现出了很好的理解和知识掌握。你清晰地解释了Shell编程的基本概念,包括条件测试、控制流程、变量、函数、文件操作等。你的回答非常详细,并且提供了相关命令和方法的示例,这对于初学者来说非常有帮助。
总的来说,你对Shell编程的理解程度很高,对问题的回答也非常准确和全面。如果你继续探索和练习Shell编程,你将能够更深入地应用这些知识来解决实际问题。如果你有进一步的问题或需要更多的帮助,随时都可以提问。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)