51、命令行处理与版本控制全解析

命令行处理与版本控制全解析

命令行处理

在使用shell时,命令行处理是一个核心环节,它涉及多个步骤,理解这些步骤对于成为shell脚本编写专家或解决复杂问题至关重要。

命令行处理步骤

每一行从标准输入(STDIN)或脚本中读取的内容被称为管道(pipeline),因为它包含一个或多个由零个或多个管道字符(|)分隔的命令。shell处理命令行的步骤如下:
1. 分割为标记 :将命令按固定的元字符(空格、制表符、换行符、;、(、)、<、>、| 和 &)分割成标记,标记类型包括单词、关键字、I/O重定向符和分号。
2. 检查首个标记 :查看每个命令的第一个标记是否为无引号或反斜杠的关键字。如果是如 if 等控制结构开头的关键字,该命令为复合命令,shell会为其内部设置相关参数,然后读取下一个命令并重新开始处理;若不是复合命令开头的关键字,shell会提示语法错误。
3. 检查别名 :将每个命令的第一个单词与别名列表进行匹配。若找到匹配项,用别名的定义替换,然后回到步骤1;若未找到,则进入步骤4。此机制允许递归别名,还能为关键字定义别名。
4. 花括号扩展 :例如 a{b,c} 会扩展为 ab ac
5. 波浪号扩展 :若波浪号(~)在单词开头,将其替换为用户的主目录($HOME)。
6. 用户主目录替换 :将 ~user 替换为用户的主目录。
7. 参数替换 :对以美元符号($)开头的表达式进行参数(变量)替换。
8. 命令替换 :对 $(string) 形式的表达式进行命令替换。
9. 算术替换 :计算 $((string)) 形式的算术表达式。
10. 单词分割 :将参数、命令和算术替换后的部分再次分割成单词,这次使用 $IFS 中的字符作为分隔符。
11. 路径名扩展 :对出现的 * ? [/] 对进行路径名扩展(通配符扩展)。
12. 命令查找 :按以下顺序查找第一个单词作为命令的来源:函数命令、内置命令、 $PATH 中任何目录下的可执行文件。
13. 执行命令 :设置好I/O重定向等操作后执行命令。

以下是一个命令行处理的示例:
假设已经执行了 alias ll="ls -l" ,用户 alice 的主目录为 /home/alice ,且有变量 $$ 的值为 2537 。现在处理命令 ll $(type -path cc) ~alice/.*$(($$%1000)) ,其处理过程如下:
1. ll $(type -path cc) ~alice/.*$(($$%1000)) 分割输入为单词。
2. ll 不是关键字,步骤2无操作。
3. ls -l $(type -path cc) ~alice/.*$(($$%1000)) ls -l 替换别名 ll ,然后重复步骤1 - 3,步骤2将 ls -l 分割为两个单词。
4. ls -l $(type -path cc) ~alice/.*$(($$%1000)) 无操作。
5. ls -l $(type -path cc) /home/alice/.*$(($$%1000)) ~alice 扩展为 /home/alice
6. ls -l $(type -path cc) /home/alice/.*$((2537%1000)) 2537 替换 $$
7. ls -l /usr/bin/cc /home/alice/.*$((2537%1000)) type -path cc 进行命令替换。
8. ls -l /usr/bin/cc /home/alice/.*537 计算算术表达式 2537%1000
9. ls -l /usr/bin/cc /home/alice/.*537 无操作。
10. ls -l /usr/bin/cc /home/alice/.hist537 用文件名替换通配符表达式 .*537
11. 找到命令 ls /usr/bin 中。
12. 执行 /usr/bin/ls 并带上选项 -l 和两个参数。

命令行处理步骤的流程可以用以下mermaid流程图表示:

graph LR
    A[分割为标记] --> B[检查首个标记]
    B --> |非关键字| C[检查别名]
    B --> |开头关键字| D[处理复合命令]
    B --> |其他关键字| E[语法错误]
    C --> |是别名| A
    C --> |非别名| F[花括号扩展]
    F --> G[波浪号扩展]
    G --> H[参数替换]
    H --> I[命令替换]
    I --> J[算术替换]
    J --> K[单词分割]
    K --> L[路径名扩展]
    L --> M[命令查找]
    M --> N[执行命令]
引用

引用是让shell跳过部分命令行处理步骤的方法,主要有单引号和双引号两种:
- 单引号(’‘) :绕过步骤1 - 10,包括别名替换。单引号内的所有字符保持不变,且单引号内不能再使用单引号,即使使用反斜杠转义也不行。
- 双引号(”“) :绕过步骤1 - 4以及步骤9和10。双引号内忽略管道字符、别名、波浪号替换、通配符扩展和通过分隔符分割单词,但允许参数替换、命令替换和算术表达式计算。可以使用反斜杠转义双引号、 $ 、反引号(`)和反斜杠本身。

以下是引用的示例表格:
| 表达式 | 值 |
| ---- | ---- |
| $person | hatter |
| "$person" | hatter |
| \$person | $person |
| '$person' | $person |
| "'$person'" | ’hatter’ |
| ~alice | /home/alice |
| "~alice" | ~alice |
| '~alice' | ~alice |

在shell编程中,除非特别需要参数、命令或算术替换,否则使用单引号更安全。

eval命令

eval 命令可以让命令行处理过程再次执行,这看似奇怪,但实际上非常强大,它能让脚本动态创建命令字符串并传递给shell执行,使脚本在运行时能修改自身行为。

下面通过示例来理解 eval 的作用:
- 简单示例: eval ls 将字符串 “ls” 传递给shell执行,shell会打印当前目录下的文件列表。
- 复杂示例:

listpage="ls | more"
$listpage

上述代码不会产生分页的文件列表,因为shell在计算变量时,管道字符在特定步骤之后才被识别,导致 | more 被当作 ls 的参数, ls 会报错找不到这些文件名。

而使用 eval $listpage 时,shell会将 ls | more 作为参数再次进行命令行处理,在步骤2中找到 | 并将命令分割为 ls more ,最终实现分页显示文件列表。

eval 是一个高级特性,需要一定的编程技巧才能有效使用,它赋予了程序类似人工智能的能力,能让程序“编写”并执行其他程序,虽然在日常shell编程中可能不常用,但值得深入理解。

版本控制

版本控制系统(Revision Control Systems)不仅能让我们追溯代码的历史,还能查看不同时间点的变更情况,也被称为版本管理系统。它允许我们维护项目文件的中央存储库,跟踪文件的更改及原因,部分系统还支持多人同时协作处理同一项目甚至同一文件。

版本控制系统在现代软件开发中至关重要,同时在文档编写、系统配置跟踪(如 /etc )和书籍创作等领域也有广泛应用。其主要优点包括:
1. 数据安全 :在存储库妥善备份的情况下,能有效防止代码丢失。
2. 变更管理 :便于实施变更控制,鼓励记录变更原因。
3. 多人协作 :支持多地人员共同参与项目,避免数据覆盖丢失。
4. 多地点工作 :允许个人在不同地点工作而不丢失进度。
5. 变更追溯 :可轻松撤销变更,查看不同版本间的具体差异(二进制文件除外),结合有效日志还能了解变更原因。
6. 关键字扩展 :通常支持在非二进制文件中嵌入版本元数据。

常见的免费和商业版本控制系统众多,下面介绍三种常见系统:CVS、Subversion和RCS,它们在主流现代操作系统中均可使用。

在使用版本控制系统前,需要确定以下几点:
1. 系统选择 :决定使用哪种版本控制系统。
2. 存储库位置 :确定中央存储库的位置(如适用)。
3. 项目结构 :规划存储库中项目或目录的结构。
4. 策略制定 :制定更新、提交、标记和分支策略。

CVS(Concurrent Versions System)

CVS是一个广泛使用且成熟的版本控制系统,提供了适用于主流现代操作系统(包括Windows)的命令行工具,部分系统还有GUI工具。

CVS的优缺点
优点 缺点
应用广泛且成熟 提交操作非原子性,可能导致存储库不一致
众多Unix管理员和开源开发者熟悉 按文件提交,如需引用一组文件需使用标签
简单项目易于使用 目录结构支持较差
便于访问远程存储库 难以在保留历史记录的同时重命名文件和目录
基于RCS,可对中央存储库进行一定修改 对二进制文件和符号链接等对象支持不佳

CVS按文件跟踪版本,每个文件有独立的内部版本号,因此单个项目不能用单一版本号跟踪,可使用标签实现此类跟踪。

CVS操作示例

以下是使用CVS的基本操作步骤:
1. 创建新存储库

/home/jp$ mkdir -m 0775 cvsroot
/home/jp$ chmod g+srwx cvsroot
/home/jp$ cvs -d /home/jp/cvsroot init
  1. 创建新项目并导入
/home/jp$ cd /tmp
/tmp$ mkdir 0700 scripts
/tmp$ cd scripts/
/tmp/scripts$ cat << EOF > hello
> #!/bin/sh
> echo 'Hello World!'
> EOF
/tmp/scripts$ cvs -d /home/jp/cvsroot import scripts shell_scripts NA
  1. 检出项目并更新
/tmp/scripts$ cd
/home/jp$ cvs -d /home/jp/cvsroot/ checkout scripts
/home/jp$ cd scripts
/home/jp/scripts$ ls -l
  1. 修改文件并检查状态
/home/jp/scripts$ echo "Hi Mom..." >> hello
/home/jp/scripts$ cvs status
/home/jp/scripts$ cvs -qn update
  1. 添加新脚本到版本控制
/home/jp/scripts$ cat << EOF > mcd
> #!/bin/sh
> mkdir -p "$1"
> cd "$1"
> EOF
/home/jp/scripts$ cvs add mcd
  1. 提交更改
/home/jp/scripts$ cvs commit
  1. 更新沙箱、再次修改并查看差异
/home/jp/scripts$ cvs update
/home/jp/scripts$ vi hello
/home/jp/scripts$ cvs diff hello
  1. 提交更改并避免使用编辑器
/home/jp/scripts$ cvs -m '* Fixed syntax error' commit
  1. 查看文件历史
/home/jp/scripts$ cvs log hello
  1. 添加版本元数据并提交
/home/jp/scripts$ vi hello
/home/jp/scripts$ cat hello
#!/bin/sh
$Id$
echo 'Hello World!'
echo 'Hi Mom...'
/home/jp/scripts$ cvs ci -m'Added ID keyword' hello

CVS的基本操作流程可以用以下mermaid流程图表示:

graph LR
    A[创建存储库] --> B[创建项目并导入]
    B --> C[检出项目]
    C --> D[修改文件]
    D --> E[检查状态]
    E --> F[添加新文件]
    F --> G[提交更改]
    G --> H[更新沙箱]
    H --> I[再次修改]
    I --> J[查看差异]
    J --> G
    G --> K[查看文件历史]
    K --> L[添加元数据]
    L --> G

通过以上介绍,我们了解了命令行处理的详细步骤、引用和 eval 命令的使用,以及版本控制系统的重要性和CVS的基本操作,这些知识对于提高编程效率和项目管理能力具有重要意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值