1. Shell的类型

Shell是用户与操作系统内核之间的命令行接口,主要分为以下几类:

1.1 Bourne Shell (sh)

  • 起源:1977年由Stephen Bourne在贝尔实验室开发
  • 特点:Unix系统的标准Shell,语法简洁,执行效率高
  • 常见位置/bin/sh
  • 现状:现代系统中通常作为其他Shell的兼容模式存在

1.2 Bash (Bourne-Again Shell)

  • 起源:1989年Brian Fox为GNU项目开发
  • 特点:sh的增强版,支持命令历史、命令行编辑、作业控制等
  • 常见位置/bin/bash
  • 现状:Linux系统和macOS的默认Shell

1.3 Zsh (Z Shell)

  • 起源:1990年由Paul Falstad开发
  • 特点:Bash的扩展,支持更强大的补全、主题和插件系统
  • 常见位置/bin/zsh
  • 现状:macOS Catalina及以后版本的默认Shell

1.4 其他Shell

  • C Shell (csh):类C语法,支持命令历史
  • Korn Shell (ksh):结合了sh和csh的特性
  • Fish:友好的交互式Shell,语法高亮和自动建议

2. Shell进程及其关系

2.1 什么是Shell进程

当用户在终端输入命令时,操作系统会创建一个Shell进程来执行该命令。每个终端会话通常对应一个Shell进程。

2.2 进程关系示例

# 查看当前Shell的进程ID
echo $$

# 查看父进程ID
echo $PPID

# 查看进程树
pstree -p $$

3. Shell的父子关系

3.1 父子进程创建

当Shell执行外部命令时,会创建子进程:

# 执行ls命令,Shell会创建子进程
ls -l

# 使用&在后台运行,同样创建子进程
sleep 60 &

3.2 进程继承关系

  • 子进程继承父进程的环境变量
  • 子进程可以修改自己的环境变量而不影响父进程
  • 子进程结束后会向父进程返回退出状态

3.3 示例:观察父子进程

# 脚本示例:parent.sh
#!/bin/bash
echo "父进程PID: $$"
echo "父进程名称: $0"

# 创建子进程
sleep 30 &
child_pid=$!
echo "子进程PID: $child_pid"

# 等待子进程结束
wait $child_pid
echo "子进程已结束,退出状态: $?"

4. Shell的运行模式

4.1 交互式模式 (Interactive Mode)

  • 特点:用户直接与Shell交互,显示提示符
  • 启动方式:直接打开终端或通过ssh连接
  • 配置文件.bashrc.zshrc
  • 示例:日常在终端中输入命令

4.2 非交互式模式 (Non-interactive Mode)

  • 特点:执行脚本或通过管道传递命令
  • 启动方式bash script.shecho "ls" | bash
  • 配置文件.bash_profile.profile
  • 示例:自动化脚本执行

4.3 登录Shell (Login Shell)

  • 特点:用户登录时启动的Shell
  • 启动方式:系统登录、su - usernamebash --login
  • 配置文件.bash_login.profile
  • 读取文件顺序
    1. /etc/profile
    2. ~/.bash_profile
    3. ~/.bash_login
    4. ~/.profile

4.4 非登录Shell (Non-login Shell)

  • 特点:在已登录会话中启动的新Shell
  • 启动方式:直接运行bash、打开新终端标签
  • 配置文件.bashrc
  • 示例:在终端中直接输入bash命令

5. 内建命令和外部命令

5.1 内建命令 (Built-in Commands)

  • 定义:直接内置于Shell解释器中的命令
  • 特点
    • 执行速度快(无需创建新进程)
    • 可以影响Shell自身状态
    • 通常用于Shell环境控制
  • 常见内建命令
    • cd:改变目录
    • echo:输出文本
    • export:设置环境变量
    • source.:执行脚本
    • exit:退出Shell

5.2 外部命令 (External Commands)

  • 定义:独立的可执行文件
  • 特点
    • 存储在文件系统中
    • 执行时需要创建新进程
    • 通过PATH环境变量查找
  • 示例
    • ls/bin/ls
    • grep/bin/grep
    • python/usr/bin/python

5.3 判断命令类型

# 使用type命令判断
type cd      # 输出: cd is a shell builtin
type ls      # 输出: ls is /bin/ls
type -a echo # 显示所有echo命令的位置

# 使用command命令强制使用外部命令
command -v ls  # 显示命令路径
builtin echo   # 强制使用内建echo

6. 内建命令history的用法

6.1 基本使用

# 查看命令历史
history

# 查看最近10条历史
history 10

# 清空历史记录
history -c

# 删除指定行历史
history -d 行号

6.2 历史记录配置

# 查看历史记录相关环境变量
echo $HISTSIZE    # 内存中保存的历史数量
echo $HISTFILESIZE # 历史文件中保存的行数
echo $HISTFILE    # 历史文件路径

# 设置历史记录选项
export HISTSIZE=5000
export HISTFILESIZE=10000
export HISTCONTROL=ignoreboth  # 忽略重复命令和空格开头的命令
export HISTTIMEFORMAT="%Y-%m-%d %H:%M:%S "  # 为历史添加时间戳

6.3 实用技巧

# 快速执行历史命令
!!        # 执行上一条命令
!-2       # 执行倒数第二条命令
!ls       # 执行最近以ls开头的命令
!?data?   # 执行最近包含data的命令

# 搜索历史命令
Ctrl+R    # 反向搜索历史
Ctrl+S    # 正向搜索历史(可能需要stty设置)

# 历史命令替换
^old^new  # 将上一条命令中的old替换为new后执行
!!:gs/old/new/  # 全局替换

6.4 历史记录管理

# 将当前会话历史追加到文件
history -a

# 从历史文件重新加载历史
history -r

# 将内存历史写入文件并清空内存
history -w && history -c

7. 内建命令alias的用法

7.1 创建别名

# 基本语法
alias 别名='原命令 参数'

# 常用示例
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
alias grep='grep --color=auto'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'

# 带参数的别名(需要使用函数)
alias lsd='ls -d */'  # 只显示目录

7.2 查看别名

# 查看所有别名
alias
alias -p

# 查看特定别名
alias ll
alias ls grep

7.3 删除别名

# 删除单个别名
unalias ll

# 删除所有别名
unalias -a

7.4 永久化别名

# 添加到Shell配置文件
# ~/.bashrc (Bash) 或 ~/.zshrc (Zsh)

# 示例.bashrc内容
alias ll='ls -alF'
alias ..='cd ..'
alias ...='cd ../..'
alias ....='cd ../../..'
alias h='history'
alias j='jobs -l'
alias path='echo -e ${PATH//:/\\n}'

7.5 实用别名示例

# 系统监控
alias cpu='top -o cpu'
alias mem='top -o rsize'
alias ports='netstat -tulanp'

# Git相关
alias gs='git status'
alias ga='git add'
alias gc='git commit'
alias gp='git push'
alias gl='git log --oneline --graph --all'

# 安全相关
alias rm='rm -i'      # 删除前确认
alias cp='cp -i'      # 覆盖前确认
alias mv='mv -i'      # 覆盖前确认

# 网络相关
alias myip='curl ifconfig.me'
alias ping='ping -c 5'
alias ports='netstat -tulanp'

# 开发相关
alias py='python3'
alias pip='pip3'
alias venv='python3 -m venv'

7.6 别名与函数结合

# 创建带参数的别名函数
# 在.bashrc或.zshrc中添加
mkcd() {
    mkdir -p "$1" && cd "$1"
}

# 使用
mkcd new_project

8. 总结

Shell作为用户与操作系统交互的重要桥梁,理解其类型、进程关系、运行模式以及内建命令的使用,能够显著提高命令行工作效率。通过合理使用history和alias,可以打造个性化的高效工作环境。

8.1 最佳实践建议

  1. 选择合适的Shell:根据需求选择Bash、Zsh等
  2. 理解进程关系:避免不必要的子进程创建
  3. 配置运行模式:正确设置登录和非登录Shell的配置文件
  4. 善用历史记录:配置HISTCONTROL和HISTTIMEFORMAT
  5. 创建实用别名:将常用命令组合封装为别名

8.2 进一步学习资源

  • Bash官方文档:man bash

  • Zsh官方文档:man zsh

  • Advanced Bash-Scripting Guide

  • ShellCheck工具:静态Shell脚本分析

  • 请添加图片描述

  • 请添加图片描述
    请添加图片描述

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐