SHELL

一、从系统组成角度说明 Shell 存在的必要性

要理解 Shell 的必要性,我们需要先了解操作系统的层次结构:

操作系统层次模型:

┌─────────────────────────────────────────┐
│           应用程序 (Applications)        │  ← 用户直接使用的软件
├─────────────────────────────────────────┤
│             Shell (命令行解释器)         │  ← 用户与系统内核的"翻译官"
├─────────────────────────────────────────┤
│             系统调用接口 (System Calls)   │  ← 应用程序与内核的桥梁
├─────────────────────────────────────────┤
│           操作系统内核 (Kernel)          │  ← 核心资源管理器
├─────────────────────────────────────────┤
│             硬件资源 (Hardware)           │  ← CPU、内存、磁盘等
└─────────────────────────────────────────┘

Shell 的核心作用:

  1. 用户与内核的桥梁**内核** 直接管理硬件资源(CPU、内存、磁盘、网络等),但普通用户无法直接与内核交互Shell 作为"命令解释器",接收用户输入的命令,翻译成内核能理解的指令,再将内核的执行结果返回给用户

  2. 保护系统安全Shell 对用户命令进行解析和验证,防止恶意或错误的命令直接损害内核通过权限机制控制用户对系统资源的访问

  3. 提供统一的交互接口无论底层硬件如何变化,Shell 为用户提供一致的命令行操作体验隐藏了复杂的硬件操作细节,简化了系统使用

简单比喻:Shell 就像是计算机系统的"前台接待员"或"翻译官" - 用户告诉接待员想要什么,接待员转达给后台(内核),再把结果返回给用户。

Shell 作为用户与操作系统内核之间的关键桥梁,其重要性体现在:

  • 必要性:保护内核安全,提供统一接口,简化系统操作

  • 脚本化:通过编写脚本实现自动化,提高效率

  • 强大功能:历史、补全、重定向、管道等特性提升使用体验

  • 灵活性:变量、控制结构等编程特性支持复杂逻辑实现

掌握 Shell 脚本编程是系统管理、 DevOps 和自动化运维的基础技能,建议通过实际编写脚本来巩固这些概念。

shell的发展:

  • 1971年:Ken Thompson 开发了第一个 Unix Shell(Thompson Shell)

  • 1977年:Stephen Bourne 在贝尔实验室开发了 Bourne Shell (sh),成为 Unix 的标准 Shell

  • 1978年:Bill Joy 在伯克利开发了 C Shell (csh),引入了类C语法

  • 1983年:David Korn 开发了 Korn Shell (ksh),结合了 sh 和 csh 的优点

  • 1989年:Brian Fox 为 GNU 项目开发了 Bash (Bourne-Again Shell)

  • 1990年:Paul Falstad 开发了 Z Shell (zsh)

根据2024年的数据:

  • Bash: ~80% (Linux默认,最流行)

  • Zsh: ~15% (macOS默认,快速增长)

  • 其他: ~5% (ksh, csh, fish等)


二、Shell 脚本的基本元素

一个完整的 Shell 脚本通常包含以下基本元素:

1. Shebang(释伴)

#!/bin/bash
  • 必须是脚本的第一行,以 #!开头

  • 指定执行此脚本的解释器路径

  • 常见的有:#!/bin/bash, #!/bin/sh, #!/usr/bin/python

2. 注释

# 这是单行注释
​
: '
***冒号后面加空格***
这是多行注释
可以写多行内容
'

3. 命令

  • 系统命令:ls, cp, mkdir

  • 控制结构:if, for, while

  • 函数调用等

4. 变量

name="value"

5. 输入输出

  • 输入:

    • 1.直接赋值:name="li si"

    • 2.read命令: read name

    • 3.使用位置参数($1 $2 $3…) : name=$1

    • 4.命令输入:name=$(whoami)

    • 注意:在命令行中定义:退出当前进程后该变量就失效,其他终端上无法使用该变量(切换到其他用户、退出重新登录)

var='xiaoming2'
var="`cmd`"
var="$(cmd)"
ip1=192.168.1.251
school="Peking University"
today1=`date +%F` # 注意为反引号``
today2=$(date +%F)
  • 输出:echo, printf

一、输入:read 命令

read命令用于从标准输入(键盘)或文件中读取数据,并将其赋值给变量。

1. 基本 read 语法
# 基本读取
read variable_name
​
# 带提示信息的读取
read -p "提示信息: " variable_name
​
# 读取多个变量
read var1 var2 var3
​
# 从文件描述符读取
read -u fd variable_name
2. 基本读取示例
#!/bin/bash
​
# 基本读取
echo "请输入您的名字:"
read name
echo "你好, $name!"
​
# 一行完成提示和读取
read -p "请输入您的年龄: " age
echo "您今年 $age 岁"
​
# 读取多个值
echo "请输入三个数字(用空格分隔):"
read num1 num2 num3
echo "您输入的数字是: $num1, $num2, $num3"
​
3. read 命令的常用选项

-p:显示提示信息

#!/bin/bash
​
# 使用 -p 选项显示提示
read -p "请输入用户名: " username
read -p "请输入密码: " -s password  # -s 用于隐藏输入
echo  # 换行
echo "用户: $username, 密码已设置"

-t:设置超时时间

#!/bin/bash
​
# 5秒超时
if read -t 5 -p "请在5秒内输入内容: " input; then
    echo "您输入了: $input"
else
    echo "时间到,未输入任何内容"
    exit 1
fi

-n:限制输入字符数

#!/bin/bash
​
# 读取固定长度
read -n 5 -p "请输入5个字符: " text
echo
echo "您输入了: $text"

二、输出:echo 命令

echo命令用于输出文本到标准输出。

1. 基本 echo 语法
# 基本输出
echo "Hello World"
​
# 输出变量
echo "变量值: $variable"
​
# 输出多个参数
echo "第一个" "第二个" "第三个"
​
# 输出到文件
echo "内容" > file.txt
echo "追加内容" >> file.txt
2. echo 选项

-n:不输出尾随换行符

#!/bin/bash
​
echo -n "正在处理..."
sleep 2
echo "完成"
​
# 输出:正在处理...完成(在同一行)

-e:启用反斜杠转义

#!/bin/bash
​
# 启用转义字符解释
echo -e "第一行\n第二行"
echo -e "制表符:\t前\t后"
​
echo -e "回退\b字符"  # 删除前一个字符
​
# 转义序列:
# \b  退格
# \c  不继续输出(相当于 -n)
# \e  转义字符
# \f  换页
# \n  换行
# \r  回车
# \t  水平制表符
# \v  垂直制表符
# \\  反斜杠

-E:禁用反斜杠转义(默认)

#!/bin/bash
​
# 禁用转义(默认行为)
echo -E "第一行\n第二行"
# 输出:第一行\n第二行(原样输出)
3. echo 高级用法
#!/bin/bash
​
# 输出彩色文本
echo -e "\033[31m红色文字\033[0m"
echo -e "\033[32;44m绿字蓝底\033[0m"
​
# 定义颜色函数
red() { echo -e "\033[31m$@\033[0m"; }
green() { echo -e "\033[32m$@\033[0m"; }
​
red "这是错误信息"
green "这是成功信息"
​
​
三、输出:printf 命令

printf命令提供更强大的格式化输出功能,类似于 C 语言的 printf 函数。

1. 基本 printf 语法
printf format-string [arguments...]
2. 格式说明符
说明符描述示例
%s字符串printf "%s" "hello"
%d十进制整数printf "%d" 100
%f浮点数printf "%.2f" 3.14159
%x十六进制整数printf "%x" 255
%c字符printf "%c" 65(输出 A)
%b字符串(解释反斜杠转义)printf "%b" "line1\nline2"
3. printf 基本用法
#!/bin/bash
​
# 基本格式化
printf "姓名: %s, 年龄: %d\n" "张三" 25
​
# 宽度和对齐
printf "%-10s %5d\n" "Alice" 30    # 左对齐
printf "%10s %5d\n" "Bob" 25       # 右对齐
=======
[root@rhce ~]# a=Alice
[root@rhce ~]# b=3
[root@rhce ~]# printf "%-10s %5d\n" "$a"  "$b"  
Alice          3
[root@rhce ~]# 
=======
​
# 浮点数格式化
printf "π ≈ %.2f\n" 3.14159
# 前导零
printf "带前导零: %05d\n" 42
​
# 千位分隔符(某些系统支持)
printf "千位分隔: %'d\n" 1234567
​
四、输入输出重定向
#!/bin/bash
​
# 输出重定向
echo "内容" > file.txt          # 覆盖写入
echo "追加内容" >> file.txt     # 追加写入
​
# 输入重定向
read var < file.txt            # 从文件读取
wc -l < file.txt               # 统计行数
​
# 错误输出重定向
command 2> error.log           # 错误信息重定向
command > output.log 2>&1      # 标准输出和错误都重定向
command &> all_output.log      # 同上(更简洁)
​
# here document
[root@rhce ~]# passwd << end
redhat
redhat
> end
更改用户 root 的密码 。
新的密码: 无效的密码: 密码少于 8 个字符
重新输入新的密码: passwd:所有的身份验证令牌已经成功更新。
​

三、Shell 脚本编写规范

良好的编写规范提高脚本的可读性和可维护性:

1. 文件命名规范

  • 使用 .sh扩展名,如 backup_files.sh

  • 文件名应见名知意,使用小写字母和下划线

2. 脚本头部信息

#!/bin/bash
# 脚本名称: system_info.sh
# 描述: 显示系统基本信息
# 作者: Your Name
# 创建日期: 2024-10-28
# 版本: 1.0
​
​
#编辑.sh文件时自动生成关于脚本文件说明的注释
[root@localhost ~]# cat /root/.vimrc
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1,"#!/bin/bash")
call setline(2,"#########################")
call setline(3,"#File name:".expand("%"))
call setline(4,"#Version:v1.0")
call setline(5,"#Email:admin@test.com")
call setline(6,"#Created time:".strftime("%F %T"))
call setline(7,"#Description:")
call setline(8,"#########################")
call setline(9,"")
endif
endfunc

3. 代码格式规范

  • 运算符两边加空格:name="value"name = "value"

  • 流程控制语句格式规范:

# 好的格式
if [ condition ]; then
    commands
fi
​
for item in list; do
    commands
done

4. 变量命名规范

  • 局部变量使用小写:file_name

  • 常量使用大写:MAX_RETRY=3

  • 环境变量使用大写:DATABASE_URL

四、Shell 脚本执行方法

1. 作为可执行文件执行(推荐)

# 添加执行权限
chmod +x script.sh
​
# 执行脚本
./script.sh

2. 指定解释器执行

# 不需要执行权限
bash script.sh
sh script.sh

3. 使用 source 或点号执行

# 在当前Shell环境中执行,变量会保留
source script.sh
. script.sh    # 点号+空格+脚本名

4. 三种执行方式的区别:

执行方式语法是否创建子Shell环境变量影响
./script.sh需要执行权限不影响父Shell
bash script.sh直接执行不影响父Shell
source script.sh在当前Shell执行影响当前Shell

示例验证:

# 创建测试脚本 test_env.sh
echo "当前Shell PID: $$"
export TEST_VAR="hello"
​
***说明:使用 export导出,变量可被子进程继承
​
# 方式1:创建子Shell
./test_env.sh    # 显示子Shell的PID,TEST_VAR不会影响当前环境
​
# 方式2:在当前Shell执行
source test_env.sh  # 显示当前Shell的PID,TEST_VAR会在当前环境生效
echo $TEST_VAR      # 输出: hello

五、Shell 脚本退出状态码

1. 什么是退出状态码?

  • 每个命令执行后都会返回一个数字状态码

  • 0表示成功,非 0表示失败

  • 通过 $?变量获取上一个命令的退出状态

2. 常见状态码含义:

状态码含义说明
0成功命令执行成功
1一般性错误未知错误
2误用Shell命令权限不足等
126命令不可执行没有执行权限
127命令未找到命令不存在
128+N信号N终止如 130=128+2 (Ctrl+C)
255退出状态越界超出0-255范围

3. 自定义退出状态码

#!/bin/bash
​
check_file() {
    if [ -f "$1" ]; then
        echo "文件存在"
        return 0    # 成功
    else
        echo "文件不存在"
        return 1    # 失败
    fi
}
​
check_file "/etc/passwd"
echo "检查结果: $?"
​
# 脚本退出时指定状态码
if [ $? -eq 0 ]; then
    exit 0    # 成功退出
else
    exit 1    # 失败退出
fi

实验:

创建一个简单的系统信息报告脚本,输出基本的系统状态信息(当前登录用户名称、报告生成时间、磁盘使用情况、内存使用情况)

#!/bin/bash
# 简单的系统信息报告脚本
# 作者:[您的姓名]
# 创建日期:$(date +%Y-%m-%d)
​
# 定义变量
REPORT_TITLE="=== 系统基本信息报告 ==="
CURRENT_USER=$(whoami)
CURRENT_TIME=$(date)
DISK_USAGE=$(df -h /)
MEMORY_INFO=$(free -h)
​
# 输出报告
echo $REPORT_TITLE
echo "报告生成时间: $CURRENT_TIME"
echo "当前用户: $CURRENT_USER"
echo ""
echo ""
echo "磁盘使用情况 (根分区):"
echo "$DISK_USAGE"
echo ""
echo "内存使用情况:"
echo "$MEMORY_INFO"
echo ""
echo "=== 报告结束 ==="

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值