﻿---
title: Shell 编程
date: 2024-06-19
excerpt: Shell的启动和功能简介 shell识别的命令形式 输入输出重定向和管道 shell变量和引用符 Shell脚本程序的建立与运行 shell的语句类别 流编辑器sed和报表生成器awk简介
tags:
  - Linux
  - Shell
cover: https://assets.vluv.space/cover/OS/Ch8-Shell.webp
---

<script data-swup-reload-script type="module" src="/js/components/tab.js"></script>

## 常用命令

`read`、`expr`、`tput` 等都是 Linux 系统上的外部命令，可以在各种 Shell 脚本中调用。

### read

`read` 从标准输入读取一行并赋值给变量。支持多个选项控制读取行为。

**常用选项:**

```bash
-p "prompt" # 显示提示信息
-s          # 静默模式，不显示输入
-t seconds  # 超时时间
-n chars    # 读取指定字符数后返回
```

<x-tabs>

<x-tab title="单变量赋值" active>

```bash
read var
# 将读入的全部数据赋给 var
```

</x-tab>

<x-tab title="多变量赋值">

```bash
read var1 var2 var3
# 第一个参数赋给 var1，第二个赋给 var2，其余参数赋给最后一个变量
```

</x-tab>

<x-tab title="带提示信息">

```bash
read -p "Enter your name: " name
echo "Hello, $name"
```

</x-tab>

</x-tabs>

如果执行 `read` 时标准输入无数据，程序会等待数据输入或被终止。

**示例:**

```bash
$ read name age
[stdin] yilan 23
$ echo "student $name is $age years old"
[stdout] student yilan is 23 years old
```

### tput

`tput` (terminal put) 用于终端控制，可以设置光标位置、颜色、清屏等。它与终端控制代码数据库 `terminfo` 相连，根据 `TERM` 环境变量值读取相应终端的控制代码。

**常用功能:**

```bash
tput clear       # 清屏
tput cup row col # 移动光标到指定位置
tput bold        # 粗体文本
tput smso        # 启动突出显示
tput rmso        # 结束突出显示
tput sgr0        # 重置所有属性
tput cols        # 输出终端列数
tput lines       # 输出终端行数
```

## Bash 语法

### 常用系统变量

```bash
$0    # 当前 shell 程序的名字
$1-$9 # 命令行上的第一到第九个参数
$#    # 命令行上的参数个数(不包含 $0)
$*    # 命令行上的所有参数
$@    # 分别用双引号引用命令行上的所有参数
$$    # 当前进程的进程标识号 (PID)
$?    # 上一条命令的退出状态
$!    # 最后一个后台进程的进程标识号
```

### Bash 特殊字符

Bash 中使用多种括号和特殊字符，理解它们的含义和用法非常重要。

#### 命令替换

```bash
$(command) # 反撇号，引用命令的运行结果
$(command) # $() 语法，功能与反撇号相同，更推荐使用
```

#### 条件测试

```bash
[ string ]   # 传统条件测试，两侧必须保留空格
[[ string ]] # Bash 扩展条件测试，两侧保留空格，支持模式匹配
```

#### 算术运算

```bash
((expr)) # 算术运算，无需转义 * 和 /
```

#### 分组与代码块

```bash
(command)    # 在子 shell 中执行
{ command; } # 在当前 shell 中执行，command 后的分号和空格不可省略
```

### 条件判断

**注意:** `[ condition ]` 中的方括号两侧必须保留空格，否则条件测试无法正确执行。

`if`、`else` 和 `elif` 的基本语法:

<x-tabs>

<x-tab title="if 基本语法" active>

```bash
if [ condition ]; then
  # 条件为真时执行的代码
fi
```

</x-tab>

<x-tab title="if-else 基本语法">

```bash
if [ condition ]; then
  # 条件为真时执行的代码
else
  # 条件为假时执行的代码
fi
```

</x-tab>

<x-tab title="if-elif-else 基本语法">

```bash
if [ condition1 ]; then
  # condition1 为真时执行
elif [ condition2 ]; then
  # condition1 为假但 condition2 为真时执行
else
  # 所有条件都为假时执行
fi
```

</x-tab>

</x-tabs>

#### 字符串测试

```bash
-z STRING          # 如果字符串为空，则为真
-n STRING          # 如果字符串不为空，则为真
STRING1 = STRING2  # 如果两个字符串相等，则为真
STRING1 != STRING2 # 如果两个字符串不相等，则为真
```

#### 数值比较

```bash
NUM1 -eq NUM2          # 如果两个数字相等，则为真
NUM1 -ne NUM2          # 如果两个数字不相等，则为真
NUM1 -gt NUM2          # 如果 NUM1 大于 NUM2，则为真
NUM1 -ge NUM2          # 如果 NUM1 大于或等于 NUM2，则为真
NUM1 -lt NUM2          # 如果 NUM1 小于 NUM2，则为真
NUM1 -le NUM2          # 如果 NUM1 小于或等于 NUM2，则为真
[[ $string =~ regex ]] # 如果字符串匹配正则表达式，则为真
```

#### 文件测试

```bash
-e FILE # 如果文件存在，则为真
-f FILE # 如果文件存在且是普通文件，则为真
-d FILE # 如果文件存在且是目录，则为真
-r FILE # 如果文件存在且可读，则为真
-w FILE # 如果文件存在且可写，则为真
-x FILE # 如果文件存在且可执行，则为真
```

#### 逻辑运算符

```bash
&&   # 逻辑与
||   # 逻辑或
```

### 循环语句

<x-tabs>

<x-tab title="for 循环" active>

```bash
for ((counter = 1; counter <= 5; counter++)); do
  echo "Welcome, this is iteration number $counter."
done
```

</x-tab>

<x-tab title="while 循环">

```bash
counter=0

# 循环直到用户输入的数字等于 5
while [ $counter -ne 5 ]; do
  echo "Enter a number (current count: $counter)"
  read input_number

  # 检查输入是否为数字
  if ! [[ "$input_number" =~ ^[0-9]+$ ]]; then
    echo "Error: Please enter a valid number."
    continue # 如果输入无效，跳过当前循环的剩余部分
  fi

  # 将输入的数字赋值给计数器
  counter=$input_number

  # 打印当前计数器的值
  echo "You entered: $counter"
done
```

</x-tab>

<x-tab title="case 语句">

```bash
echo "Enter a number between 1 and 3:"
read number

case $number in
1) echo "You entered one." ;;
2) echo "You entered two." ;;
3) echo "You entered three." ;;
*) echo "You did not enter a number between 1 and 3." ;;
esac
```

</x-tab>

</x-tabs>