💭 写在前面:Shell 是一个命令行解释器,它可以用于自动化任务、脚本编写和系统管理等多种场景。本章我们将学习 Shell 编程基础,介绍变量和一些基础语句。本篇文章旨在为初学者提供 Shell 编程的基础知识,我们希望本篇文章能够帮助读者更好地理解 Shell 编程的核心概念和语法,并且能够在实践中运用它们(在讲解时会提供示例)。
在 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
定义只读变量 readonly:
$ flower = tulip
$ readonly flower # 定义flower变量未只读变量
$ flower=rose
bash: flower: readonly variable
变量只在声明的 shell 内使用,但是使用 export 命令,可使变量也可以在其他地方使用:
$ cat kfc
echo $day V me 50!$ day=FuckingCrazyThursday # 定义变量day
$ ./kfc
V me 50! # 此时环境变量未导出$ export day # 我们用 export 来导出
$ ./kfc
FuckingCrazyThursday V me 50! # 此时再运行,变量起效了
特殊 shell 变量,即 "Automatic shell variables",是指由 Shell 自动设置和维护的一组特殊变量,它们用于在 Shell 脚本中处理命令行参数、脚本执行状态等信息。这些变量可以在脚本中 直接使用,而无需自己声明和定义。
这里执行成功状态码是 0!“在C语言中,都是0为假,1为真; 而在Shell脚本语言中,状态码0表示成功(可以理解为真),其他状态码(包括1)表示错误(可以理解为假);
$ ls /nonexistent
ls: cannot access '/nonexistent': No such file or directory # 失败
$ echo $? # 返回上一个命令退出码
2 # 返回非0值# 这里的 ls /nonexistent 命令执行失败,其退出状态码为 2。
$ 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 份数据。
标准 Shell 变量 (Standard shell variable) 是指在 Shell 中预先定义好的一组标准变量,它们的名称和含义都是固定的。这些变量通常用于在 Shell 脚本中传递参数、保存状态和结果等。
下面我们来介绍几个常用的标准变量:
斜杠(\):转义字符,将其视为一个字符。
单引号(' '):按原样处理单引号内的字符串。
双引号(" "):将双引号内的变量替换为变量值进行处理。
$ echo $HOME
/home/foxny $ echo '$HOME' # 将单引号内的内容看作字符串。我就想打印 $HOME
$HOME # 没触发 $HOME,而是老老实实打印出了 $HOME$ echo \$home # \ 转义,这里把 $ 看成字符
$HOME # $ 被当做字符看待了,所以不会触发HOME$ echo "$home" #
/home/foxny
如果不希望解析变量,直接按照字符原样输出内容,就可以使用单引号。
而双引号会首先解析变量的内容,单引号则是不触发解析!
一种方式是 ./ 的方式,一般要 chmod 给执行权限:
vim test.sh # 打开脚本
chmod -x test.sh # 添加权限
./test.sh # 运行脚本
当然,也可以使用 bash 直接运行:
bash test.sh
if 条件
then语句
else语句
fi # 结尾用fi结尾(finish)
如果条件为真,则执行 then
后面的命令;否则执行 else
后面的命令。
if [ "$FILE1" = "$FILE2" ]
then
...
fi
if test "$FILE1" = "$FILE2"
then
...
fi
举个例子:
if [ "$1" == "hello" ]
thenecho "Hello, world!"
elseecho "Goodbye, world!"
fi# 如果在脚本执行时传递了参数 "hello" 则输出 "Hello, world!"
# 否则输出 "Goodbye, world!"
如果想并行,就需要加分号,就像这样:
if [ "$1" == "hello" ]; thenecho "Hello, world!"
elseecho "Goodbye, world!"
fi
while 条件
do语句
done
如果条件为真,则执行 语句 中的命令,并继续测试条件;如果条件为假,则跳出循环。
举个例子:计算 1 到 4 之间的整数的平方,并输出结果。它使用一个 while 循环,将 $int 变量从 1递增到 4,并在每次循环中计算平方。在每个循环迭代中,它使用 expr 命令计算平方值,然后将其存储在变量$sq中,并使用 echo 命令将 $sq 的值输出到控制台。
int=1
while [ $int -lt 5 ]
dosq=`expr $int \* $int`echo $sq int=`expr $int + 1`
done
echo "Job complete"
for 变量 in 列表
do语句
done
列中可以是用空格或换行符分隔的多个值。每次循环中,变量会依次取值列表中的每个值,并执行语句。当列表中的值都遍历完毕时,for
循环结束。
举个例子:
IFS=:for dir in $PATH
dols -ld $dir
done
与 while 语句类似,但条件的测试方式相反,是 while 的否定形式。
* 相当于 Python 中的 while not,C/C++ 中 while (! )
until 条件
do语句
done
如果条件为假,则执行语句中的命令,并继续测试条件;如果条件为真,则跳出循环。
int=1
until [ $int -ge 5 ]
dosq=`expr $int \* $int`echo $sq int=`expr $int + 1`
done
echo "Job complete"
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
在 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 |