linux基础-shell基础
1.shell基础
Shell 本质就是 Linux 的命令解释器,我们敲的命令都是 Shell 翻译给内核的。常用:bash(默认)、sh、zsh。
第一行解释器声明,告诉系统我们在用什么执行
#! /bin/bash
一个简单的测试系统时间的脚本

3 种执行方式
- 赋予权限直接执行:
chmod +x test.sh && ./test.sh - 用 bash 调用:
bash test.sh(不需要执行权限) - 加载到当前 shell:
source test.sh或. test.sh(会影响当前终端环境)

几种常见的执行方式
2.变量:shell最基础的存储单元
1.自定义变量
自定义变量的定义,等号两边都不能有空格
name="xiaobai" #等号两边都能有空格,否则会当成命令执行
变量命名规则
1. 不能包含字母、数字、下划线
2. 不能以数字开头
3. 区分大小写
在引用变量的过程中最好是加花括号防止后面跟着字母有歧义
name="xiaobai"
# 1.直接引用
echo $name # 输出:xiaobai
# 2. 加花括号能防止歧义
echo "我的名字是${name}abc" #防止歧义$nameabc,没有这个变量
设置只读变量&&删除变量
# 只读变量且不能修改
readonly PI=3.14
PI=123 # 不能修改,只读会报错
#删除变量
unset name
echo $name #输出为空
2.环境变量
环境变量是系统预定义的变量,所有子进程都能继承和访问
常用的环境变量
| 变量名 | 含义 |
|---|---|
PATH | 命令搜索路径,用冒号分隔 |
HOME | 当前用户的家目录 |
PWD | 当前工作目录 |
USER | 当前用户名 |
HOSTNAME | 主机名 |
SHELL | 当前使用的 Shell 解释器 |
自定义环境变量
# 定义局部变量(只有当前shell能访问)
LOCAL_VAR="local"
#升级为环境变量(所有子shell都能访问)
export GLOBAL_VAR="global"
3.特殊变量
shell预定义的变量,获取脚本运行信息
#!/bin/bash
echo "脚本名称:$0"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "总参数个数:$#"
echo "所有参数(整体):$*"
echo "所有参数(分开):$@"
echo "上一条命令退出码:$?"
echo "当前脚本进程ID:$$"
运行后的效果

重点:$*和$@的区别
只有在用双引号包裹时,它们的区别才会体现:
"$*":把所有参数当成一个整体"$@":把所有参数当成独立的个体
下面示例
#!/bin/bash
echo "--- 遍历\$* ---"
for arg in "$*"; do
echo $arg
done
echo "--- 遍历\$@ ---"
for arg in "$@"; do
echo $arg
done
最后执行的情况遍历的此时不同,第一个只循环一次,第二个循环3次

最常用的 $?
含义:是上一条命令的退出状态码
规则:0表示执行成功,非0表示失败
主要用于判断上一条命令是否执行成功
ls /nonexistent # 访问一个不存在的目录
echo $? # 输出:2(表示失败)
ls /home
echo $? # 输出:0(表示成功)
最后执行情况,明显2是失败的没有这个目录,而 /home是真实存在的

3.输入输出管道符
1.输入命令 echo:最常用的输出命令
# 普通输出
echo "Hello World"
# 输出换行(默认会换行)
echo -n "1234" # -m末尾取消换行
# 输出转义字符
echo -e "第一行\n第二行\t制表符"
printf:格式化输出 与c语言的printf用法一致,适合输出规整的表格
printf "姓名:%s,年龄:%d\n" "xiaobai" 20
printf "姓名:%s,年龄:%d\n" "小白" 25
2. 输入命令:read
从终端中读取用户输入
# 基本用法
read name
echo "你输入的名字是:$name"
# 带提示的输入(-p)
read -p "请输入你的年龄是" age
echo "你的年龄是:" $age
# 隐藏输入(-s)
read -s -p "请输入密码" password
echo -e "\n输入密码完成"
3.重定向
Linux中一切皆文件,每个进程默认打开3个文件描述符
| 文件描述符 | 名称 | 含义 |
|---|---|---|
| 0 | 标准输入 (stdin) | 从键盘输入 |
| 1 | 标准输出 (stdout) | 输出到终端 |
| 2 | 标准错误 (stderr) | 错误信息输出到终端 |
重定向就是把这些默认输入输出改到其他地方
常用的重定向语法
| 语法 | 含义 |
|---|---|
命令 > 文件 | 把标准输出覆盖写入文件 |
命令 >> 文件 | 把标准输出追加写入文件 |
命令 2> 文件 | 把标准错误覆盖写入文件 |
命令 2>> 文件 | 把标准错误追加写入文件 |
命令 &> 文件 | 把标准输出和标准错误一起覆盖写入文件 |
命令 &>> 文件 | 把标准输出和标准错误一起追加写入文件 |
命令 < 文件 | 从文件读取输入 |
# 将ls的结果输入到file.txt(覆盖)
ls home > file.txt
# 追加写入
echo "内容" >> file.txt
# 把错误信息写入error.log
ls /nonexistent 2> error.log
# 把所有的输出都不显示
ls /home &>/dev/null
4.管道符
将前一个命令的标准输出,作为后一个命令的标准输入
# 统计当前目录下的文件个数
ls | wc -l
# 过滤包含nginx的进程
ps -ef | grep nginx
# 提取磁盘使用率
df -h / | grep / | awk '{print $5}'
注意管道两边都是在子shell中执行的,所以管道内变量不会影响外部
count=0
ls | while read line; do
count=$((count+1))
done
echo $count
# 输出:0(因为while在子Shell中执行,外部count没有被修改)
4.条件判断 if/test/[]
shell中所有的条件判断,本质都是test命令,而[]是test的别名,基本语法
1.基本语法
# 写法1:用test命令
if test 条件; then
命令
fi
# 写法2:用[ ](推荐,更常用)条件两边必须有空格
if [ 条件 ]; then
命令
elif [ 条件 ]; then
命令
else
命令
fi
# if也能用(())作为条件,例如
if (( num == 1 )); then
echo "数字为1"
else
echo "数字不为1"
fi
2.三类常用判断
(1)文件目录判断
| 符号 | 含义 |
|---|---|
-f 文件 | 判断是否是普通文件 |
-d 目录 | 判断是否是目录 |
-e 文件/目录 | 判断是否存在 |
-r 文件 | 判断是否可读 |
-w 文件 | 判断是否可写 |
-x 文件 | 判断是否可执行 |
-s 文件 | 判断文件是否非空(大小大于 0) |
示例:判断是目录还是文件shell脚本
file="file.txt"
if [ -f "$file" ]; then
echo "$file是普通文件"
elif [ -d "$file" ]; then
echo "$file是目录"
else
echo "$file不存在"
fi
(2)数值大小比较
| 符号 | 含义 |
|---|---|
-eq | 等于(equal) |
-ne | 不等于(not equal) |
-gt | 大于(greater than) |
-lt | 小于(less than) |
-ge | 大于等于(greater or equal) |
-le | 小于等于(less or equal) |
大于gt、小于lt、等于eq、不等于ne、大于等于ge等,记住前4个,以及首字母就可
read -p "请输入年龄" age;
if [ $age -lt 18 ]; then
echo "未成年"
else
echo "成年"
fi
(3)字符串判断
| 符号 | 含义 |
|---|---|
str1 = str2 | 字符串相等 |
str1 != str2 | 字符串不相等 |
-z str | 字符串为空(长度为 0) |
-n str | 字符串非空 |
示例
name="zhangsan"
if [ -z "$name" ]; then
echo "名字不能为空"
elif [ "$name" != "zhangsan" ] # 两边一定要空格
echo "名字不为张三"
else
echo "你是张三"
fi
3.拓展[[]](bash特有)
[[ ]]是 bash 对[ ]的增强,支持更多功能:
- 支持正则匹配
- 逻辑运算符
&&和||不需要转义 - 字符串比较不需要加双引号(不会因为空格报错)
示例
# 正则匹配;判断字符串是否是以a开头
str="apple"
if[[ $str = ~^a.* ]]; then
echo "字符串以a开头"
fi
# 逻辑运算符更加简洁
if [[ $a -gt 10 && $b -lt 20 ]]; then
echo "条件满足"
fi
5.循环结构:for / while / until
1.for循环(最常用)
示例1:遍历列表
# 遍历数字列表
for i in 1 2 3 4 5; do
echo "数字:$i"
done
# 遍历字符串列表
for name in zhangsan lisi wangwu zhouliu; do
echo "名字:$"
done
# 遍历连续数字
for i in {1..10};do
echo $i
done
# 带步长的连续数字:{开始..结束..步长}
for i in {1..10..2}; do
echo $i # 输出:1 3 5 7 9
done
示例2:遍历文件
遍历当前目录下的所有txt文件
for file in *.txt; do
echo "处理文件:$file"
done
示例3:c语言风格for循环
for((i=0; i<10; i++)); do
echo $i
done
2.while循环
当条件为真的时候执行循环
i=1
while [ $i -le 5 ]; do
echo $i
i=$((i+1))
done
在算数计算的时候一般要用双括号,里面要进行的是数学计算不是字符串操作
常用场景:逐一进行文件读取
# 逐行读取file.txt内容
while read line; do
echo "行内容:$line"
done < file.txt
3.until循环
和while相反,当条件为假的时候执行循环
i=1
util [ $i -gt 5 ]; do
echo $i
i=$((i+1))
done
4.循环控制
break:跳出整个循环
coutinue:跳过本次循环,继续下一次
for i in {1..10}; do
if [ $q -eq 5 ]; then
continue # 跳过i=5
fi
if [ $q -eq 8 ]; then
break # 跳出循环,i=8后面的都不执行
fi
echo $i
done
6.逻辑预算符
| 符号 | 含义 | 用法 | 说明 | ||||
|---|---|---|---|---|---|---|---|
&& | 逻辑与(短路与) | cmd1 && cmd2 | 仅当cmd1成功(退出码0)时,才执行cmd2 | ||||
| ` | ` | 逻辑或(短路或) | `cmd1 | cmd2` | 仅当cmd1失败(退出码≠0)时,才执行cmd2 | ||
! | 逻辑非(取反) | ! cmd | 反转cmd的退出状态码(成功变失败,失败变成功) |
示例
# 如果文件存在,就删除他
[ -f test.txt ] && rm test.txt
# 如果目录不存在,就创建他
[ -d test_dir ] || mkdir test_dir
# 组合使用
[ -f test.txt ] && echo "文件存在" || echo "文件不存在"
7. 函数封装复用
1.函数定义与调用
hellow() {
echo "hello"
}
# 直接调用函数
hello
2.函数参数的传递
greet() {
echo "参数一 $1"
echo "参数二 $2"
echo "所有参数 $#"
}
调用参数传递
greep "zzx" 40
3.函数返回值
shel脚本只能返回0~255之间的整数
返回值用return语句,不写默认返回最后一条命令的退出嘛
调用者通过$?获取返回值
# 计算两个数的和
add() {
sum=$(( $1 + $2 ))
return $sum
}
add 10 20
echo "和是:$?"
若返回字符串后者大于255的数字,不能用return,应该用echo输出,然后用$()捕获,例如一下形式

8.脚本调试
命令行调试
# 执行脚本时,打印每一条执行的命令
sh -x demo.sh

其他有用的 set 选项
set -e:脚本中任何命令执行失败,立即退出脚本set -u:使用未定义的变量时,脚本报错并退出set -o pipefail:管道中任何命令失败,整个管道命令失败
9.简单脚本练习
1.接收两个参数,输出和、差、积、商

更加完善健壮性
#!/bin/bash
# 四则运算函数:用法 sum 数字1 数字2 运算符
sum() {
# 先检查参数数量是否正确
if [ $# -ne 3 ]; then
echo "用法错误!正确用法:$0 数字1 数字2 运算符"
echo "支持的运算符:+ - * /"
return 1
fi
# 用 [[ ]] 做字符串比较,更安全,不需要转义特殊字符
if [[ $3 == "+" ]]; then
echo $(( $1 + $2 ))
elif [[ $3 == "-" ]]; then
echo $(( $1 - $2 )) # 修正:减法逻辑
elif [[ $3 == "*" ]]; then
echo $(( $1 * $2 ))
elif [[ $3 == "/" ]]; then
# 整数除法,添加除数为0的检查
if [ $2 -eq 0 ]; then
echo "错误:除数不能为0"
return 1
fi
echo $(( $1 / $2 ))
else
echo "错误:请使用四则运算符 + - * /"
return 1
fi
}
# 测试调用示例(替换成你自己的参数即可)
echo "10 + 5 = $(sum 10 5 +)"
echo "10 - 5 = $(sum 10 5 -)"
echo "10 * 5 = $(sum 10 5 *)"
echo "10 / 5 = $(sum 10 5 /)"
2.判断数字为奇数还是偶数

更加完善健壮性
#!/bin/bash
# 1. 提示用户输入数字
read -p "请输入一个整数: " num
# 2. 验证输入是否为有效整数(支持正负数和0)
if [[ ! $num =~ ^-?[0-9]+$ ]]; then
echo "错误:请输入有效的整数!"
exit 1
fi
# 3. 用取模运算判断奇偶(除以2看余数)
if (( num % 2 == 0 )); then
echo "$num 是偶数"
else
echo "$num 是奇数"
fi
3.打印/var/log目录下一.log结尾的文件,打印文件名
IFS= read -r line 是 Shell 中逐行读取文件的「黄金标准写法」,核心目的是100% 原样保留文件中的每一行内容,避免 Shell 自动 “篡改” 数据

写入临时文件的方式读取文件
#!/bin/bash
# 定义临时文件路径(脚本所在目录)
temp_file="$(dirname "$0")/file.txt"
# 把ls结果写入临时文件
ls /var/log > "$temp_file"
# 标准read写法,原样保留所有字符
while IFS= read -r line; do
echo "行内容:$line"
done < "$temp_file"
# 脚本结束自动删除临时文件
rm -f "$temp_file"
4.编写一个函数,接收一个文件名作为参数,判断该文件是否存在,如果存在则打印文件大小


健壮型代码
#!/bin/bash
# 函数功能:检查文件是否存在,存在则打印大小
# 用法:check_file_size "文件名"
check_file_size() {
# 1. 验证参数数量(必须传1个文件名)
if [ $# -ne 1 ]; then
echo "错误:请传入且仅传入1个文件名作为参数!"
echo "用法示例:check_file_size \"/var/log/syslog\""
return 1
fi
# 用local定义局部变量,避免污染全局环境
local file="$1"
# 2. 检查文件是否存在且是普通文件(-f)
if [ -f "$file" ]; then
# 获取文件大小(字节数)
# Linux用 stat -c %s;macOS请改成 stat -f %z
local size_bytes=$(stat -c %s "$file")
# 获取人类可读大小(自动转换 KB/MB/GB)
local size_human=$(du -h "$file" | cut -f1)
echo "✅ 文件 \"$file\" 存在"
echo " 大小(字节):$size_bytes"
echo " 大小(可读):$size_human"
else
echo "❌ 文件 \"$file\" 不存在或不是普通文件"
return 1
fi
}
# ---------------- 测试示例 ----------------
echo "=== 测试1:存在的文件 ==="
check_file_size "/etc/passwd"
echo -e "\n=== 测试2:不存在的文件 ==="
check_file_size "/tmp/nonexistent_file.txt"
echo -e "\n=== 测试3:带空格的文件名(需用引号包裹) ==="
# 先创建一个测试文件
touch "my file.txt"
check_file_size "my file.txt"
# 清理测试文件
rm -f "my file.txt"
5.编写一个脚本将目录下所有的.txt文件都改为.bak
| 符号 | 删除方向 | 记忆技巧 |
|---|---|---|
# | 从字符串开头删 | 键盘上 # 在 $ 的左边(开头) |
% | 从字符串末尾删 | 键盘上 % 在 $ 的右边(末尾) |
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)