💭 写在前面:Shell 是一个命令行解释器,它可以用于自动化任务、脚本编写和系统管理等多种场景。本章我们将学习 Shell 编程基础,介绍变量和一些基础语句。本篇文章旨在为初学者提供 Shell 编程的基础知识,我们希望本篇文章能够帮助读者更好地理解 Shell 编程的核心概念和语法,并且能够在实践中运用它们(在讲解时会提供示例)。
本篇博客全站热榜排名:未上榜
Ⅰ. Shell 变量
0x00 基本变量
在 Shell 编程中,变量是一个非常重要的概念,因为它们可以用于存储和操作数据,以及传递值给函数和脚本。命令行解释器 (Bourne Shell) 无需声明变量即可使用,变量的名称默认使用 大写字母:
$ name=foxny $ echo $name # 打印变量,变量前要加 $ foxny $ name=牛魔酬宾 # 修改变量内容 $ echo $name 牛魔酬宾
📌 注意定义规则:
$ name=my computer bash: computer: command not found $ name="my computer" $ echo $name my computer $ ux=UNIX $ echo ${ux}tm UNIXtm $ echo "$ux"tm UNIXtm $ echo $uxtm bash: uxtm: unbound variable $ set -u $ echo Suxtm
0x01 只读变量:readonly
定义只读变量 readonly:
$ flower = tulip $ readonly flower # 定义flower变量未只读变量 $ flower=rose bash: flower: readonly variable
0x02 环境变量设置:export
变量只在声明的 shell 内使用,但是使用 export 命令,可使变量也可以在其他地方使用:
$ cat kfc echo $day V me 50! $ day=FuckingCrazyThursday # 定义变量day $ ./kfc V me 50! # 此时环境变量未导出 $ export day # 我们用 export 来导出 $ ./kfc FuckingCrazyThursday V me 50! # 此时再运行,变量起效了
0x03 特殊变量(Automatic shell variables)
特殊 shell 变量,即 "Automatic shell variables",是指由 Shell 自动设置和维护的一组特殊变量,它们用于在 Shell 脚本中处理命令行参数、脚本执行状态等信息。这些变量可以在脚本中 直接使用,而无需自己声明和定义。
- $?:返回上一个命令的退出状态码。如果命令 执行成功,则状态码为 0,否则为非零值。
这里执行成功状态码是 0!“在C语言中,都是0为假,1为真; 而在Shell脚本语言中,状态码0表示成功(可以理解为真),其他状态码(包括1)表示错误(可以理解为假);
$ ls /nonexistent ls: cannot access '/nonexistent': No such file or directory # 失败 $ echo $? # 返回上一个命令退出码 2 # 返回非0值 # 这里的 ls /nonexistent 命令执行失败,其退出状态码为 2。
- $$:返回当前 Shell 进程的 , $$ 是一个常量,只要脚本在执行,它的值就不会改变:
$ echo $$ # 返回进程pid 24085
$!
:返回最近一个后台运行的进程的 ,与 $$ 不同的是, $? 是一个变量,其值随着后台作业的启动和结束而改变:
$ sleep 10 & [1] 1234 $ echo $! 1234 # 这里的sleep 10 &命令被放到后台运行,并输出了进程ID1234,然后使用 $! 获取该进程ID
$#
:获取脚本传入的参数个数,获取传递给当前 Shell 脚本(或函数)的参数个数。
$ myscript.sh arg1 arg2 arg3 3 # 在 myscript.sh 脚本中可以通过 $# 获取到传递给它的参数个数,即3。
$*
和$@
:它们功能相似,都是包含所有传递给当前 Shell 脚本或函数的参数的变量。不同的是,$* 是
将所有参数视为一个单词,而$@
则将每个参数视为一个单独的单词。
注意:当 $* 和 $@ 不被双引号 " "
包围时,它们之间没有任何区别,都是将接收到的每个参数看做一份数据,彼此之间以空格来分隔。但是当它们被双引号 " "
包含时,就会有区别了:
$*
将所有的参数从整体上看做一份数据,而不是把每个参数都看做一份数据。(*普遍代表所有,*(星号) 是 Linux 中的通配符,代表一个或一个以上的所有字符)
$@
将每个参数都看作一份数据,彼此之间是独立的。(这就像我们单独艾特某个人一样,理解!)
$ echo "Using \$* : $*" Using $* : arg1 arg2 arg3 $ echo "Using \$@ : $@" Using $@ : arg1 arg2 arg3 # $* 把三个参数视为单个单词,并将它们连接起来, # 使用空格作为分隔符。而 $@ 则将每个参数视为一个单独的单词。 # 比如传递了 3 个参数:那么对于 $*来说,这 3 个参数会合并到一起形成 1 份数据,它们之间是无法分割的。 # 而对于 $@ 来说,这 3 个参数是相互独立的,它们是 3 份数据。
0x04 标准 Shell 变量(Standard shell variable)
标准 Shell 变量 (Standard shell variable) 是指在 Shell 中预先定义好的一组标准变量,它们的名称和含义都是固定的。这些变量通常用于在 Shell 脚本中传递参数、保存状态和结果等。
下面我们来介绍几个常用的标准变量:
- $ HOME:当前用户的家目录。
- $ PATH:搜索可执行文件的路径。
- $ IFS:输入字段分隔符,用于分割输入字符串。
- $ CDPATH:指定 cd 命令在搜索目录时的搜索路径。
- $ LOGNAME:登陆的用户名
- $ SHELL:登陆时展现的路径位置(默认 Shell 路径)
- $ PS1:登录时命令提示符的格式,用于显示当前 shell 的状态和提示用户输入 ($ #)
- $ TERM:接收的 terminal,用于指定当前终端的类型
- $ PWD:当前工作目录。
- $ OLDPWD:上一个工作目录。
- $ USER:当前用户名。
- $ GROUPS:当前用户所属的组。
- $ HOSTNAME:当前主机名。
- $ OSTYPE:当前操作系统类型。
0x05 特殊引用字符
斜杠(\):转义字符,将其视为一个字符。
单引号(' '):按原样处理单引号内的字符串。
双引号(" "):将双引号内的变量替换为变量值进行处理。
$ echo $HOME /home/foxny $ echo '$HOME' # 将单引号内的内容看作字符串。我就想打印 $HOME $HOME # 没触发 $HOME,而是老老实实打印出了 $HOME $ echo \$home # \ 转义,这里把 $ 看成字符 $HOME # $ 被当做字符看待了,所以不会触发HOME $ echo "$home" # /home/foxny
如果不希望解析变量,直接按照字符原样输出内容,就可以使用单引号。
而双引号会首先解析变量的内容,单引号则是不触发解析!
Ⅱ. Shell 基本语句介绍
0x00 脚本运行
一种方式是 ./ 的方式,一般要 chmod 给执行权限:
vim test.sh # 打开脚本 chmod -x test.sh # 添加权限 ./test.sh # 运行脚本
当然,也可以使用 bash 直接运行:
bash test.sh
0x01 if 语句
if 条件 then 语句 else 语句 fi # 结尾用fi结尾(finish)
如果条件为真,则执行 then
后面的命令;否则执行 else
后面的命令。
if [ "$FILE1" = "$FILE2" ] then ... fi
if test "$FILE1" = "$FILE2" then ... fi
举个例子:
if [ "$1" == "hello" ] then echo "Hello, world!" else echo "Goodbye, world!" fi # 如果在脚本执行时传递了参数 "hello" 则输出 "Hello, world!" # 否则输出 "Goodbye, world!"
如果想并行,就需要加分号,就像这样:
if [ "$1" == "hello" ]; then echo "Hello, world!" else echo "Goodbye, world!" fi
0x02 while 语句
while 条件 do 语句 done
如果条件为真,则执行 语句 中的命令,并继续测试条件;如果条件为假,则跳出循环。
举个例子:计算 1 到 4 之间的整数的平方,并输出结果。它使用一个 while 循环,将 $int 变量从 1递增到 4,并在每次循环中计算平方。在每个循环迭代中,它使用 expr 命令计算平方值,然后将其存储在变量$sq中,并使用 echo 命令将 $sq 的值输出到控制台。
int=1 while [ $int -lt 5 ] do sq=`expr $int \* $int` echo $sq int=`expr $int + 1` done echo "Job complete"
0x03 for 语句
for 变量 in 列表 do 语句 done
列中可以是用空格或换行符分隔的多个值。每次循环中,变量会依次取值列表中的每个值,并执行语句。当列表中的值都遍历完毕时,for
循环结束。
举个例子:
IFS=: for dir in $PATH do ls -ld $dir done
0x04 until 语句
与 while 语句类似,但条件的测试方式相反,是 while 的否定形式。
* 相当于 Python 中的 while not,C/C++ 中 while (! )
until 条件 do 语句 done
如果条件为假,则执行语句中的命令,并继续测试条件;如果条件为真,则跳出循环。
int=1 until [ $int -ge 5 ] do sq=`expr $int \* $int` echo $sq int=`expr $int + 1` done echo "Job complete"
0x05 case 语句
case 表达式 in 匹配模式1 ) 语句 ;; 匹配模式2 ) 语句 ;; ... * ) 语句 ;; esac # 结尾要加 esac(就倒过来的 case,这很有趣)
举个例子:
echo "It is morning? yes or no" read timeofday case "$timeofday" in yes | y | Yes | YES ) echo "Good Morning" ;; n* | N* ) echo "Good Afternoon" ;; * ) echo "What The Fuck?" ;; esac
0x06 函数
在 Shell 脚本中,函数是一段可以重复使用的代码块,可以接受参数,并返回一个值。定义函数的基本语法如下:
函数名() { 语句 }
💭 举个例子:计算两个数的和的函数
add() { sum=$(($1 + $2)) return $sum }
📌 [ 笔者 ] 王亦优 📃 [ 更新 ] 2023.3.17 ❌ [ 勘误 ] /* 暂无 */ 📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免, 本人也很想知道这些错误,恳望读者批评指正!
📜 参考资料 C++reference[EB/OL]. []. http://www.cplusplus.com/reference/. Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. . 百度百科[EB/OL]. []. https://baike.baidu.com/. 比特科技. Linux[EB/OL]. 2021[2021.8.31 xi |