Shell 基础介绍
Shell 的语言属性与本质
- Shell 是一种程序设计语言。作为命令语言,它交互式解释和执行用户输入的命令或者自动地解释和执行预先设定好的一连串的命令;作为程序设计语言,它定义了各种变量和参数,并提供了许多在高级语言中才具有的控制结构,包括循环和分支。
- Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
- Shell 既是一种命令语言,又是一种程序设计语言。
Shell 编程与种类
- Shell 编程跟 JavaScript、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
- Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(/usr/bin/sh 或 /bin/sh )
- Bourne Again Shell(/bin/bash )
- C Shell(/usr/bin/csh )
- K Shell(/usr/bin/ksh )
- Shell for Root(/sbin/sh )
- 在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash 。
- #! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序
Shell 脚本创建与代码解析
- 打开文本编辑器 (可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh ,扩展名为 sh(sh 代表 shell ),扩展名并不影响脚本执行,见名知意就好。
输入一些代码,第一行一般是这样: #!/bin/bash echo "Hello world !"
- 代码解析
- #! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell 。
- echo 命令用于向窗口输出文本。
作为可执行程序运行脚本:
- 保存代码为
test.sh
,进入脚本所在目录。 chmod +x ./test.sh
:赋予脚本执行权限。./test.sh
:执行脚本(需用./
指定当前目录,避免系统在PATH
路径找命令)。
- 保存代码为
作为解释器参数运行脚本:
直接调用 Shell 解释器执行脚本,如/bin/sh test.sh
(无需提前给脚本加执行权限 )。
2. Shell 基础语法范畴
属于 Shell 编程 “基础语法” 部分,涵盖:变量、参数传递、字符串、数组、运算符,以及 echo
/ printf
(输出)、read
(输入)、test
(条件测试)等核心命令 。
简单说,这是教你 “怎么写、怎么跑” Shell 脚本 的基础操作指南,和 Shell 语法体系的前置知识 。
一、Shell 变量
变量是 Shell 编程的基本组成部分,用于存储数据,默认以字符串形式存储,无需显式声明类型。
定义变量
支持三种定义方式,赋值号=
周围不能有空格:
variable=value
variable='value'
variable="value"
命名规范:由数字、字母、下划线组成,必须以字母或下划线开头,不能使用 Shell 关键字。
示例:
url=http://www.shujia.com
echo $url
name='数加学院'
echo $name
author="shell编程"
echo $author
使用变量
在变量名前加$
,推荐用${变量名}
明确边界:
author="linux"
echo $author # 输出:linux
echo ${author} # 输出:linux
示例(明确边界):
skill="Java"
echo "I am good at ${skill}web" # 输出:I am good at Javaweb
修改变量值
直接重新赋值,变量名前不加$
:
url="http://www.shujia.com"
echo ${url} # 输出:http://www.shujia.com
url="http://www.shujia.com/shell/"
echo ${url} # 输出:http://www.shujia.com/shell/
单引号与双引号的区别
- 单引号
' '
:原样输出,不解析变量和命令。 - 双引号
" "
:解析变量和命令。
示例:
url="http://www.shujia.com"
website1='数加学院网站:${url}' # 单引号,不解析
website2="数加学院网站:${url}" # 双引号,解析
echo $website1 # 输出:数加学院网站:${url}
echo $website2 # 输出:数加学院网站:http://www.shujia.com
命令结果赋值给变量
- 方式 1:
variable=
命令 ``(反引号,不推荐) - 方式 2:
variable=$(命令)
(推荐,区分度高)
- 方式 1:
只读变量
用readonly
定义,值不可修改:myUrl="http://www.shujia.com" readonly myUrl myUrl="http://www.shujia.com/new" # 报错:无法修改只读变量
删除变量
用unset
,不能删除只读变量:myUrl="http://www.shujia.com" unset myUrl echo $myUrl # 无输出
二、Shell 传递参数
执行脚本时可传递参数,脚本内通过
$n
获取($0
为脚本文件名)。基本用法
示例:
#!/bin/bash
echo "shell传递参数实例!"
echo "执行的文件名:$0"
echo "第一个参数为:$1"
echo "第二个参数为:$2"
echo "第三个参数为:$3"
执行./test.sh 1 2 3
,输出:
shell传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3
2
特殊字符处理参数
参数处理 | 说明 |
---|---|
$# |
传递到脚本的参数个数 |
$* |
所有参数以单字符串显示(如 "$1 $2 ... $n") |
$$ |
脚本运行的当前进程 ID 号 |
$! |
后台运行的最后一个进程的 ID 号 |
$@ |
与$* 类似,但加引号后返回每个参数(如 "$1" "$2" ... "$n") |
$? |
最后命令的退出状态(0 为无错误,非 0 为有错误) |
$*
与$@
的区别- 相同点:均引用所有参数。
- 不同点:双引号中,
"$*"
等价于 "1 2 3"(一个参数),"$@"
等价于 "1" "2" "3"(三个参数)。
三、Shell 字符串
字符串是 Shell 中最常用的数据类型,支持单引号、双引号、无引号三种形式。
三种形式的区别
形式 特点 单引号 ' '
任何字符原样输出,不解析变量和命令;不能包含单引号(即使转义)。 双引号 " "
解析变量和命令;可包含转义的双引号( \"
)。无引号 解析变量;不能包含空格(否则空格后内容被视为其他变量 / 命令)。 示例:
n=74 str1=www.shujia.com$n # 无引号,解析变量 str2="shell \"script\" $n" # 双引号,解析变量和转义 str3='数加学院 $n' # 单引号,不解析 echo $str1 # 输出:www.shujia.com74 echo $str2 # 输出:shell "script" 74 echo $str3 # 输出:数加学院 $n
获取字符串长度
格式:${#string_name}
示例:str="http://www.shujia.com" echo ${#str} # 输出:21
字符串拼接
直接将字符串并排,无需运算符:name="Shell" url="http://www.shujia.com" str1=$name$url # 无空格 str2="$name $url" # 双引号中可加空格 str3=$name":"$url # 可加其他字符 echo $str1 # 输出:Shellhttp://www.shujia.com echo $str2 # 输出:Shell http://www.shujia.com echo $str3 # 输出:Shell:http://www.shujia.com
字符串截取
截取方式 格式 说明 从左边指定位置 ${string: start :length}
start
为起始位置(从 0 计数),length
为长度(省略则到末尾)。从右边指定位置 ${string: 0-start :length}
start
为起始位置(从 1 计数),length
为长度(省略则到末尾)。从指定字符右边(第一次匹配) ${string#*chars}
忽略左边所有字符,截取 chars
右边内容。从指定字符右边(最后一次匹配) ${string##*chars}
忽略左边所有字符,截取最后一个 chars
右边内容。从指定字符左边(第一次匹配) ${string%*chars}
忽略右边所有字符,截取 chars
左边内容。从指定字符左边(最后一次匹配) ${string%%*chars}
忽略右边所有字符,截取最后一个 chars
左边内容。
url="http://www.shujia.com/index.html"
echo ${url#*://} # 输出:www.shujia.com/index.html(截取://右边)
echo ${url##*/} # 输出:index.html(截取最后一个/右边)
echo ${url%/*} # 输出:http://www.shujia.com(截取最后一个/左边)
四、Shell 数组
Bash Shell 仅支持一维数组,初始化无需指定大小,下标从 0 开始。
定义数组
格式:array_name=(元素1 元素2 ... 元素n)
(元素用空格分隔)
示例:my_array=(A B "C" D)
读取数组元素
格式:${array_name[index]}
示例echo ${my_array[0]} # 输出:A echo ${my_array[1]} # 输出:B
关联数组
支持用字符串 / 整数作下标,需用declare -A
声明:declare -A site # 声明关联数组 site["google"]="www.google.com" site["taobao"]="www.taobao.com" echo ${site["google"]} # 输出:www.google.com
获取所有元素
用${array_name[@]}
或${array_name[*]}
:my_array=(A B C D) echo ${my_array[@]} # 输出:A B C D
获取数组长度
用${#array_name[@]}
或${#array_name[*]}
:my_array=(A B C D) echo ${#my_array[@]} # 输出:4
获取数组长度
用${#array_name[@]}
或${#array_name[*]}
:my_array=(A B C D) echo ${#my_array[@]} # 输出:4
五、Shell 运算符
Shell 支持多种运算符,需通过
expr
等工具实现算术运算。算术运算符(假定
a=10
,b=20
)运算符 说明 示例 +
加法 expr $a + $b
→ 30-
减法 expr $a - $b
→ -10*
乘法(需转义 \*
)expr $a \* $b
→ 200/
除法 expr $b / $a
→ 2%
取余 expr $b % $a
→ 0=
赋值 a=$b
→a=20
==
相等(数字比较) [ $a == $b ]
→ false!=
不相等(数字比较) [ $a != $b ]
→ true示例:
a=10; b=20
echo `expr $a + $b` # 输出:30
关系运算符(仅支持数字,假定
a=10
,b=20
)运算符 说明 示例 -eq
等于 [ $a -eq $b ]
→ false-ne
不等于 [ $a -ne $b ]
→ true-gt
大于 [ $a -gt $b ]
→ false-lt
小于 [ $a -lt $b ]
→ true-ge
大于等于 [ $a -ge $b ]
→ false-le
小于等于 [ $a -le $b ]
→ true布尔运算符
运算符 说明 示例 !
非 [ ! $a -eq $b ]
→ true-a
与 [ $a -lt 100 -a $b -gt 15 ]
→ true-o
或 [ $a -lt 5 -o $b -gt 100 ]
→ false逻辑运算符
运算符 说明 示例 &&
逻辑与 [[ $a -lt 100 && $b -gt 100 ]]
→ false` ` 逻辑或 `[[ $a -lt 100 $b -gt 100 ]]` → true 字符串运算符(假定
a="abc"
,b="efg"
)运算符 说明 示例 =
字符串相等 [ $a = $b ]
→ false!=
字符串不相等 [ $a != $b ]
→ true-z
字符串长度为 0 [ -z $a ]
→ false-n
字符串长度不为 0 [ -n "$a" ]
→ true$
字符串不为空 [ $a ]
→ true文件测试运算符
运算符 说明 示例 -b file
是否为块设备文件 [ -b $file ]
→ false-c file
是否为字符设备文件 [ -c $file ]
→ false-d file
是否为目录 [ -d $file ]
→ false-f file
是否为普通文件 [ -f $file ]
→ true-r file
是否可读 [ -r $file ]
→ true-w file
是否可写 [ -w $file ]
→ true-x file
是否可执行 [ -x $file ]
→ true-s file
是否非空(大小 > 0) [ -s $file ]
→ true-e file
是否存在(含目录) [ -e $file ]
→ true
六、echo 命令
用于输出字符串,支持多种格式控制。
基本用法
- 显示普通字符串:
echo "It is a test"
或echo It is a test
- 显示转义字符:
echo "\"It is a test\""
→ 输出:"It is a test" - 显示变量:结合
read
命令读取输入并输出:
- 显示普通字符串:
#!/bin/sh
read name # 从标准输入读取
echo "$name It is a test"
-
- 执行后输入 "OK",输出:
OK It is a test
- 执行后输入 "OK",输出:
控制换行
- 换行:
echo -e "OK!\nIt is a test"
(-e
开启转义,\n
换行)
输出:
- 换行:
OK!
It is a test
-
- 不换行:
echo -e "OK! \cIt is a test"
(\c
不换行)
输出:OK! It is a test
- 不换行:
输出定向到文件
echo "内容" > file
(覆盖)或echo "内容" >> file
(追加)原样输出
用单引号:echo '${name}'
→ 输出:${name}显示命令结果
用反引号:echo
date`` → 输出当前日期时间
七、printf 命令
格式化输出,语法:printf format-string [arguments...]
格式替代符
%s
:字符串;%d
:整数;%c
:字符;%f
:小数。- 修饰符:
%-10s
(左对齐,占 10 字符)、%-4.2f
(保留 2 位小数)。
示例:
printf "%-10s %-8s %-4.2f\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543
输出:
姓名 性别 体重kg
郭靖 男 66.12
杨过 男 48.65
转义序列
序列 说明 \a
警告字符(BEL) \b
后退 \c
抑制结尾换行 \n
换行 \r
回车 \t
水平制表符 \\
反斜杠
八、read 命令
读取键盘输入,语法:read [-options] [variables]
(无变量则存到REPLY
)。
常用选项
选项 说明 -a array
赋值给数组(从下标 0 开始) -d delimiter
以 delimiter
为结束符(不含该字符)-n num
读取 num
个字符-p prompt
显示提示信息 -s
静默模式(不显示输入,如密码) -t seconds
超时时间(秒) 实例
- 读取多个输入:
read -p "Enter info > " name url age
echo "网站:$name, 网址:$url, 年龄:$age"
- 输入 “数加 http://www.shujia.com 6”,输出:
网站:数加, 网址:http://www.shujia.com, 年龄:6
- 读取单个字符:
read -n 1 -p "Enter a char> " char echo $char # 输入"1",输出:1
九、test 命令
检查条件是否成立,支持数值、字符、文件测试。
数值测试
表达式 说明 test $a -eq $b
a
等于b
test $a -ne $b
a
不等于b
test $a -gt $b
a
大于b
... 同关系运算符 示例:
num1=100; num2=100 if test $num1 -eq $num2; then echo "相等" else echo "不等" fi # 输出:相等
字符串测试
表达式 说明 test $a = $b
字符串 a
等于b
test $a != $b
字符串 a
不等于b
test -z $a
字符串 a
长度为 0... 同字符串运算符 文件测试
同文件测试运算符,示例:file="test.sh" if test -f $file; then echo "是普通文件" fi # 输出:是普通文件
逻辑操作符
!
:非;-a
:与;-o
:或。
示例:test -f $file -a -r $file
→ 文件存在且可读。
基本语法
第三章节:Shell 流程控制
一、if-else 语句
# 单分支 if condition; then command1 ... fi # 双分支 if condition; then command1 else command2 fi # 多分支 if condition1; then command1 elif condition2; then command2 else commandN fi
判断方式
- 用
[]
:if [ $a -gt $b ]; then
(大于用-gt
,小于用-lt
) - 用
((...))
:if (( a > b )); then
(直接用>
<
) 示例:
a=10; b=20 if (( a < b )); then echo "a 小于 b" fi # 输出:a 小于 b
二、for 循环
语法:
for var in list; do command1 ... done
(list
省略则用命令行参数)示例:
for loop in 1 2 3 4 5; do echo "值: $loop" done
输出:
值: 1 值: 2 值: 3 值: 4 值: 5
三、while 语句
用于重复执行命令,语法:
while condition; do command1 ... done
示例:
- 计数输出(1-5):
int=1 while [ $int -le 5 ]; do echo $int int=$((int+1)) # 自增 done
读取键盘输入
echo "按<CTRL-D>退出" while read FILM; do echo "$FILM 是好网站" done
四、无限循环
三种形式:
# 方式1 while :; do command done # 方式2 while true; do command done # 方式3 for ((;;)); do command done
五、until 循环
与 while 相反,条件为
true
时停止,语法:until condition; do command1 ... done
示例(输出 0-9):
a=0 until [ ! $a -lt 10 ]; do # 当a>=10时停止 echo $a a=$((a+1)) done
六、case ... esac
多分支选择,语法:
case 值 in 模式1) command1 ... ;; 模式2) command2 ... ;; *) # 默认 commandN ;; esac
示例:
site="bigdata" case "$site" in "bigdata") echo "大数据" ;; "google") echo "Google" ;; *) echo "其他" ;; esac # 输出:大数据
七、跳出循环
break
:跳出所有循环。
示例:while :; do read aNum if [ $aNum -gt 5 ]; then break # 大于5则跳出 fi done
continue
:跳出当前循环。
示例:while :; do read aNum if [ $aNum -gt 5 ]; then continue # 大于5则跳过本次循环 fi done
第四章节:Shell 函数
一、函数语法
定义格式:
[function] funname() { action; [return int;] # 可选,返回值0-255 }
示例:
# 无返回值 hello() { echo "这是我的第一个函数" } hello # 调用,输出:这是我的第一个函数 # 有返回值 add() { return $(($1 + $2)) } add 2 3 echo $? # 输出:5(用$?获取返回值)
二、函数参数
函数内用
$n
获取参数($1
第一个参数,$10
需用${10}
)。示例:
funwithParam() { echo "第一个参数: $1" echo "第十个参数: ${10}" echo "参数总数: $#" } funwithParam 1 2 3 4 5 6 7 8 9 10 11 # 调用
输出:
第一个参数: 1 第十个参数: 10 参数总数: 11
特殊字符同传递参数(
$#
、$*
等)。第五章节:Shell 输入 / 输出重定向
重定向用于改变命令的输入 / 输出源(默认终端)。
一、重定向命令
命令 说明 command > file
输出重定向到 file
(覆盖)command < file
输入重定向到 file
command >> file
输出追加到 file
n > file
文件描述符 n
重定向到file
n >> file
文件描述符 n
追加到file
n>&m
合并输出文件 m
和n
n<&m
合并输入文件 m
和n
<<tag
从 tag
开始到tag
结束的内容作为输入(文件描述符:0=stdin,1=stdout,2=stderr)
二、输出重定向
- 覆盖:
command > file
示例:who > users
(who
命令结果写入users
) - 追加:
command >> file
示例:echo "内容" >> users
(添加到users
末尾) 三、输入重定向
command < file
(命令从file
获取输入)
示例:wc -l < users
(统计users
行数,不显示文件名)四、重定向深入
- 重定向 stderr:
command 2> file
(错误输出到file
) - 合并 stdout 和 stderr:
command > file 2>&1
或command &> file
五、/dev/null 文件
写入内容被丢弃,用于 “禁止输出”:
- 屏蔽 stdout:
command > /dev/null
- 屏蔽 stdout 和 stderr:
command > /dev/null 2>&1
- 同时重定向 stdin 和 stdout:
command < infile > outfile
(从infile
读,输出到outfile
)