Linux shell脚本编写基础
一、shell入门
1.1 介绍
shell是一个命令解释器,它的作用是解释执行用户输入的命令以及程序等。用户每输入一条命令,shell就执行一条。这种从键盘输入命令,就可以立即得到回应的对话方式,称为交互的方式。
当命令或程序语句不在命令行下执行,而是通过一个程序文件来执行时,该程序文件就被称为shell脚本。 在shell脚本里内置了很多命令、语句及循环控制,然后将这些命令一次性执行完毕,这种通过文件执行脚本的方式称为非交互的方式。
1.2 shell脚本类型
shell脚本语言是弱类型语言,无需定义变量类型即可使用,在unix/linux中主要有两大类shell:
- Bourne shell:包括Bourne shell(sh)、Korn shell(ksh)、Bourne again shell;
- C shell:包括csh、tcsh两种类型;
查看系统默认的shell:echo $SHELL
查看系统支持的shell:cat /etc/shells
[root@bogon194 ~]# echo $SHELL
/bin/bash
[root@bogon194 ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
[root@bogon194 ~]#
1.3 shell脚本的执行
shell脚本的执行通常可以采用以下几种方式:
- bash filename或sh filename:这是当脚本文件本身没有执行权限时常使用的方法;
- /path/filename或./filename:当前路径下执行脚本,需要将脚本文件的权限改为可执行。然后使用脚本的绝对路径或相对路径就可以直接执行脚本了;
- source filename或.filename: 这种方法通常是使用source或 “.”(点号)读入或加载指定的shell脚本文件,然后依次执行指定的Shell脚本中的语句。这些语句将在当前父 shell 脚本进程中执行(其他几种模式都会启用新的进程执行该脚本进程)。
1.4 shell脚本编写规范
shell脚本的开发规范及习惯非常重要,虽然这些规范不是必须要遵守的,但是有了好的规范和习惯,可以大大提高开发效率,并能在后期降低对脚本的维护成本。
- 一个规范的shell脚本在第一行会指出由那个解释器来执行脚本中的内容,这一行内容在linux bash的编程一般为:#! /bin/bash 或 #! /bin/sh,bash和sh的区别,sh为bash的软连接,大多数情况下,脚本使用:#! /bin/bash 和 #! /bin/sh是没有区别的。
- 在shell脚本中,跟在 # 后面的内容表示注释,用来对脚本进行注释说明,注释部分不会被当做程序来执行,仅仅是给开发者和使用者看的,系统解释器是看不到的,更不会执行。注释可以自成一行,也可以跟在脚本命令的后面与命令在同一行。 注释尽量不要使用中文,在脚本中最好也不要有中文。
- shell脚本的开头加版本、版权等信息。
- shell脚本的命名应以.sh为扩展名。
- 成对的符号应尽量一次性写出来,然后退格在符号内增加内容,以防止遗漏。这些成对的符号包括: {}、[]、‘’、“” 等。
- 中括号[]两端至少要有1个空格,因此,键入中括号时即留出空格[ ],然后在退格键入中间内容,并确保两端都至少由一个空格。
- 对于流程控制语句,应一次性将格式写完,再添加内容。 如:一次性完成for循环语句的格式:
for
do
内容
done
- 通过缩进让代码更易读,如:
if 条件内容
then
内容
fi
- 脚本中的单引号、双引号及反引号必须为英文状态下的符号。
二、变量
简单地说,变量就是用一个固定的字符串(也可能是字符、数字等的组合)代替更多、更复杂的内容,该内容里可能还会包含变量、路径、字符串等其他内容。 变量是暂时存储数据的地方及数据标记,所存储的数据存在于内存空间中,通过正确地调用内存中变量的名字就可以读取出与变量对应的数据。
变量的赋值方法为: 先写变量名称,紧接着是= ,最后是值。中间无任何空格。 通过echo命令加上 $变量名,即可输出变量的值。
定义变量时变量名建议用大写,如 A=zy B=99;
read -p “提示信息” 变量名 #交互式赋值方法
查看变量内容echo $A 或 echo ${A}:
[root@bogon194 shell]# A=zy
[root@bogon194 shell]# B=99
[root@bogon194 shell]# echo $A
zy
[root@bogon194 shell]# echo ${A}
zy
[root@bogon194 shell]# read -p "please input C:" C
please input C:9999
[root@bogon194 shell]# echo $C
9999
2.1 赋值时使用引号
- 双引号:允许通过$符号引用其它变量的值;
- 单引号:禁止引用其它变量的值,$视为普通字符;
- ``:命令替换,提取命令执行后的输出结果;
- $():同``;
[root@bogon194 shell]# A=10
[root@bogon194 shell]# echo $A
10
[root@bogon194 shell]# B=$A+10
[root@bogon194 shell]# echo $B
10+10
[root@bogon194 shell]# C="$A+20"
[root@bogon194 shell]# echo $C
10+20
[root@bogon194 shell]# D='$A+30'
[root@bogon194 shell]# echo $D
$A+30
[root@bogon194 shell]# E=`ls`
[root@bogon194 shell]# echo $E
shell.sh
需要注意的是shell 原生bash不支持简单的数学运算,所说义$A+10为10+10。
命令替换(``、{})差不多,都是用来重组命令行的,先完成引号里的命令行,然后将其结果替换出来,再重组成新的命令行。
2.2 位置参数
位置参数是一种在调用 shell 程序的命令行中按照各自的位置决定的变量,是在程序名之后输入的参数。 位置参数之间用空格分隔,shell取第一个位置参数替换程序文件中的 $1,第二个替换 $2 , 依次类推。$0 是一个特殊变量,它的内容是当前这个shell程序的文件名,所以 $0 不是一个位置参数。
假如我现在有一个 1.sh脚本文件,内容如下:
#! /bin/bash
echo $0
echo $1
echo $(($2+$3))
当我执行时,我在文件名后加3个参数:
[root@bogon194 shell]# sh 1.sh 5 10 20
1.sh
5
30
这里的数值运算可以先忽略,后面会介绍。
2.3 预定义变量
预定义变量和环境变量相类似,也是在shell一开始就定义的变量,不同的是,用户只能根据shell的定义来使用这些变量,所有预定义变量都是由符号“$”和另一个符号组成。 常见的Shell预定义变量有以下几种。
- $# :位置参数的数量;
- $* :所有位置参数的内容;
- $? :命令执行后返回的状态,0表示没有错误,非0表示有错误;
- $$ :当前进程的进程号;
- $! :后台运行的最后一个进程号;
- $0 :当前执行的进程名(即shell程序的文件名);
- $@ 传递给脚本或函数的所有参数。被双引号" "包含时,与 $* 稍有不同,下面将会讲到。
假如我现在有一个 2.sh脚本文件,内容如下:
#!/bin/bash
echo "File Name: $0"
echo "First Parameter : $1"
echo "First Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"
当我执行时:
$sh 2.sh Zara Ali
File Name : 2.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
$* 和 $@ 都表示传递给函数或脚本的所有参数,不被双引号" "包含时,都以"$1" "$2" … "$n" 的形式输出所有参数。 但是当它们被双引号" "包含时,"$*" 会将所有的参数作为一个整体,以"$1 $2 … $n"的形式输出所有参数;"$@" 会将各个参数分开,以"$1" "$2" … "$n" 的形式输出所有参数。
下面的例子可以清楚的看到 $* 和 $@ 的区别:
#!/bin/bash
echo "\$*=" $*
echo "\"\$*\"=" "$*"
echo "\$@=" $@
echo "\"\$@\"=" "$@"
echo "print each param from \$*"
for var in $*
do
echo "$var"
done
echo "print each param from \$@"
for var in $@
do
echo "$var"
done
echo "print each param from \"\$*\""
for var in "$*"
do
echo "$var"
done
echo "print each param from \"\$@\""
for var in "$@"
do
echo "$var"
done
执行 sh 2.sh "a" "b" "c" "d",看到下面的结果:
$*= a b c d
"$*"= a b c d
$@= a b c d
"$@"= a b c d
print each param from $*
a
b
c
d
print each param from $@
a
b
c
d
print each param from "$*"
a b c d
print each param from "$@"
a
b
c
d
三、算术运算
shell中常见的算术运算符:
算术运算符 | 意义 |
+、-、*、/、% | 加法、减法、乘法、除法、取余 |
** | 幂运算 |
++、-- | 增加及减少 |
!、&&、|| | 逻辑非(取反)、逻辑与(and)、逻辑或(or) |
<、<=、>、>= | 比较符号(小于、小于等于、大于、大于等于) |
==、!= | 比较符号(相等、不等于) |
=、+=、-= | 赋值运算符、例如a+=1等价于a=a+1 |
shell中常见的算数运算命令:
运算操作符及运算命令 | 意义 |
(()) | 用于整数运算的常见运算符、效率很高 |
let | 用于整数运算、类似于(()) |
expr | 可用于整数运算,但还有很多其他功能 |
bc | linux下的一个计算器程序 |
$[] | 用于整数运算 |
3.1 (())数值运算命令的用法
双小括号(())的作用是进行数值运算与数值比较,它的效率很高,用法灵活,其操作方式如下:
运算操作符与运算命令 | 意义 |
((i=i+1)) | 运算后赋值,即将i+1的运算结果赋值给变量i。注意,不能用echo ((i=i+1))的形式输出表达式的值,但可以使用echo $((i=i+1))输出其值 |
i=A+5)) | 可以在(())前加A+5与运算后的值赋值给i |
((8>7&&5==5)) | 可以进行比较操作,还可以加入逻辑与和逻辑或,用于条件判断,if ((8>7&&5==5)) |
echo $((2+1)) | 需要直接输出运算表达式的运算结果时,可以在(())前加$ |
3.2 let运算符的用法
let运算命令的语法格式为: let 赋值表达式 ;
let 赋值表达式的功能等同于“((赋值表达式))” ;
[root@bogon194 shell]# i=1
[root@bogon194 shell]# let i=i+1
[root@bogon194 shell]# echo $i
2
3.3 expr命令的用法
expr用于计算:
语法:expr 表达式
示例:expr 2 + 2、expr 2 - 2 、expr 2 / 2
注意:运算符号和数字之间要有空格!!
[root@bogon194 shell]# expr 2 + 2
4
[root@bogon194 shell]# expr 2 - 2
0
[root@bogon194 shell]# expr 2 \* 2
4
[root@bogon194 shell]# expr 2 / 2
1
expr配合变量进行计算:
expr在shell中可配合变量进行计算,但需要用反引号将计算表达式括起来。
[root@bogon194 shell]# i=5
[root@bogon194 shell]# i=`expr $i + 5`
[root@bogon194 shell]# echo $i
10
利用expr计算字符串的长度:
[root@bogon194 shell]# char="hello"
[root@bogon194 shell]# expr length $char
5
3.4 bc命令的用法
bc 是UNIX/Linux下的计算器,除了作为计算器来使用,还可以作为命令行计算工具使用。
3.5 $[]运算符
$[]用于整数运算,示例如下:
[root@bogon194 shell]# echo $[2-5]
-3
[root@bogon194 shell]# echo $[2+5]
7
四、条件测试
通常,在shell的各种条件结构和流程控制结构中都要进行各种测试,然后根据测试结果执行不同的操作,有时候也会与 if 等条件语句相结合,来完成测试判断,以减少程序运行错误。
几种条件测试语句:
条件测试语法 | 说明 |
test 测试表达式 | 利用test命令进行条件表达式测试 |
[测试表达式] | 通过[]进行条件表达式测试 |
[[测试表达式]] | 通过[[]]进行条件表达式测试 |
((测试表达式)) | 通过(())进行条件表达式测试,一般用于if语法 |
测试表达式 test 、[] 、[[]] 、 (()) 的区别:
测试表达式符号 | test | [] | [[]] | (()) |
边界是否需要空格 | 需要 | 需要 | 需要 | 不需要 |
逻辑操作符 | ! 、-a、 -o | ! 、-a、 -o | ! 、&& 、 || | ! 、&& 、 || |
整数比较操作符 | -eq 、 -gt 、-lt、-ge 、-le | -eq 、 -gt 、-lt、-ge 、-le | -eq 、 -gt 、-lt、-ge 、-le 或 = 、> 、< 、 >= 、 <= | = 、> 、< 、 >= 、 <= |
字符串比较操作符 | = 、 == 、!= | = 、 == 、!= | = 、 == 、!= | 不支持 |
文件操作 | -d、-f、-e、-r、-s、-w、-x、-L、-nt、-ot | -d、-f、-e、-r、-s、-w、-x、-L、-nt、-ot | -d、-f、-e、-r、-s、-w、-x、-L、-nt、-ot | 不支持 |
是否支持通配符匹配 | 不支持 | 不支持 | 不支持 | 不支持 |
4.1 文件测试操作符
常用文件测试操作符 | 说明 |
-d , d的全拼为 directory | 文件存在且为目录则为真 |
-f , f的全拼为 file | 文件存在且为文件则为真 |
-e , e的全拼为 exists | 文件存在则为真 |
-s ,s的全拼为 size | 文件存在且大小不为0则为真 |
-r ,r的全拼为 read | 文件存在且可读则为真 |
-w ,w的全拼为write | 文件存在且可写则为真 |
-x ,x的全拼为executable | 文件存在且可执行则为真 |
-L ,L的全拼为link | 文件存在且为链接文件则为真 |
f1 -nt f2 ,nt的全拼为 newer than | 文件f1比文件f2新则为真 |
f1 -ot f2 ,ot的全拼为older than | 文件f1比文件f2旧则为真 |
test测试:
[root@bogon194 shell]# test -d 1.sh && echo true || echo false
false
[root@bogon194 shell]# test -f 1.sh && echo true || echo false
true
[root@bogon194 shell]# test -e 1.sh && echo true || echo false
true
[]测试:
[root@bogon194 shell]# [ -d 1.sh ] && echo true || echo false
false
[root@bogon194 shell]# [ -f 1.sh ] && echo true || echo false
true
[[]]测试:
[root@bogon194 shell]# [[ -d 1.sh ]] && echo true || echo false
false
[root@bogon194 shell]# [[ -f 1.sh ]] && echo true || echo false
true
4.2 字符串测试操作符
常用字符串测试操作符 | 说明 |
-n | 若字符串长度不为0,则为真 |
-z | 若字符串长度为0,则为真 |
“字符串1” == “字符串2” | 若字符串1等于字符串2,则为真 |
“字符串1” != “字符串2” | 若字符串1不等于字符串2,则为真 |
注: == 和 != 两端要有空格 。
test测试:
[root@bogon194 shell]# test "zy" == "zy" && echo true || echo false
true
[root@bogon194 shell]# test -n "zy" && echo true || echo false
true
[]测试:
[root@bogon194 shell]# [ "zy" == "zy" ] && echo true || echo false
true
[root@bogon194 shell]# [ -n "zy" ] && echo true || echo false
true
[[]]测试:
[root@bogon194 shell]# [[ "zy" == "zy" ]] && echo true || echo false
true
[root@bogon194 shell]# [[ -n "zy" ]] && echo true || echo false
true
4.3 整数二元比较操作符
在[]以及test中使用的比较符号 |
在(())和[[]]中使用的比较符号 |
说明 |
-eq | ==或= | 相等,全拼为 equal |
-ne | != | 不相等,全拼为 not equal |
-gt | > | 大于,全拼为 greater than |
-ge | >= | 大于等于,全拼为 greater equal |
-lt | < | 小于,全拼为 less than |
-le | <= | 小于等于 ,全拼为less equal |
- "="和"!="也可以在[]中作比较使用,但在[]中使用包含"<"和">"的符号时,需要用反斜线转义,有时不转义虽然语法不会报错,但是结果可能不对;
- 可以在[[]]中使用包含“-gt”和“-lt”的符号,但是不建议使用;
- 比较符号两端也要有空格,[] (()) [[]] 两端都要有空格;
test使用:
[root@bogon194 shell]# test 3 -eq 3 && echo true || echo false
true
[root@bogon194 shell]# test 3 -eq 4 && echo true || echo false
false
[]使用:
[root@bogon194 shell]# [ 3 -eq 3 ] && echo true || echo false
true
[root@bogon194 shell]# [ 3 -eq 4 ] && echo true || echo false
false
[[]]使用:
[root@bogon194 shell]# [[ 3 == 3 ]] && echo true || echo false
true
[root@bogon194 shell]# [[ 3 == 4 ]] && echo true || echo false
false
(())使用:
[root@bogon194 shell]# (( 3 == 3 )) && echo true || echo false
true
[root@bogon194 shell]# (( 3 == 4 )) && echo true || echo false
false
4.4 逻辑操作符
在[]和test中使用的操作符 | 在[[]]和(())中使用的操作符 | 说明 |
-a | && | and ,与,两端都为真,才为真 |
-o | || | or ,或, 两端有一个为真,就为真 |
! | ! | not ,非, 两端相反,则结果为真 |
4.5 if条件判断语句
简单条件判断:
#####单条件判断##############
if 条件判断
then
命令
else
命令
fi
#或
if 条件判断;then
命令
else
命令
fi
案例如下3.sh:
#! /bin/bash
read -p "please input number:" i
if [ $i -gt 5 ]
then
echo true
else
echo false
fi
执行:
[root@bogon194 shell]# sh 3.sh 9
please input number:12
true
双重条件判断:
###双条件判断#####
if 条件判断
then
命令
elif 条件判断
then
命令
else
命令
fi
##或
if 条件判断;then
命令
elif 条件判断;then
命令
else
命令
fi
4.6 case条件判断语句
case条件语句相当于多分支的if/elif/ellse条件语句,但是它比这些条件语句看起来更规范更工整,常被应用于实现系统服务启动脚本等企业应用场景中。
case 变量 in
one)
命令
;;
two)
命令
;;
*)
命令
esac
测试用例4.sh:
read -p "please input a number or str:" i
case $i in
[1-9])
echo "this a number"
;;
[a-z])
echo "this is a litter str"
;;
*)
echo "this is a dont known"
esac
执行结果:
[root@bogon194 shell]# sh 4.sh
please input a number or str:2
this a number
[root@bogon194 shell]# sh 4.sh
please input a number or str:d
this is a litter str
[root@bogon194 shell]# sh 4.sh
please input a number or str:&
this is a dont known
4.7 for循环语句
语法格式:
for 条件
do
命令
done
##或
for 条件;do
命令
done
4.8 while循环语句
语法格式:
while 条件
do
命令
done
4.9 break、continue、exit 循环控制语句
break 、continue在条件语句及循环语句(for、while、if等)中用于控制程序走向;而exit则用于终止所有语句并退出当前脚本。
命令 | 说明 |
break n | 如果省略 n ,则表示跳出整个循环,n 表示跳出循环的成熟 |
continue n | 如果省略 n ,则表示跳过本次循环,忽略本次循环的剩余代码,进行循环的下一次循环。n表示退到第 n 层继续循环 |
exit n | 退出当前 shell 程序,n 为上一次程序执行的状态返回值。n 也可以省略,在下一个 shell 里可通过 $? 接收 exit n 的n值 |
下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,就要使用break命令。
#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5, game is over!"
break
;;
esac
done
在嵌套循环中,break 命令后面还可以跟一个整数,表示跳出第几层循环。例如:
break n
表示跳出第 n 层循环。
下面是一个嵌套循环的例子,如果 var1 等于 2,并且 var2 等于 0,就跳出循环:
#!/bin/bash
for var1 in 1 2 3
do
for var2 in 0 5
do
if [ $var1 -eq 2 -a $var2 -eq 0 ]
then
break 2
else
echo "$var1 $var2"
fi
done
done
如上,break 2 表示直接跳出外层循环。运行结果:
1 0
1 5
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
对上面的例子进行修改:
#!/bin/bash
while :
do
echo -n "Input a number between 1 to 5: "
read aNum
case $aNum in
1|2|3|4|5) echo "Your number is $aNum!"
;;
*) echo "You do not select a number between 1 to 5!"
continue
echo "Game is over!"
;;
esac
done
运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句:
echo "Game is over!"
永远不会被执行。
同样,continue 后面也可以跟一个数字,表示跳出第几层循环。
#!/bin/bash
NUMS="1 2 3 4 5 6 7"
for NUM in $NUMS
do
Q=`expr $NUM % 2`
if [ $Q -eq 0 ]
then
echo "Number is an even number!!"
continue
fi
echo "Found odd number"
done
运行结果:
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
五、数组
在shell中,用括号来表示数组,数组元素用“空格”符号分割开。定义数组的一般形式为:
array_name=(value1 ... valuen)
例如:
array_name=(value0 value1 value2 value3)
还可以单独定义数组的各个分量:
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
可以不使用连续的下标,而且下标的范围没有限制。
读取数组元素值的一般格式是:
${array_name[index]}
例如:
valuen=${array_name[2]}
获取数组长度的方法与获取字符串长度的方法相同,例如:
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
六、echo
echo是Shell的一个内部指令,用于在屏幕上打印出指定的字符串。命令格式:
echo arg
6.1 显示转义字符
echo "\"It is a test\""
输出:
"It is a test"
6.2 显示变量
name="OK"
echo "$name It is a test"
输出:
OK It is a test
同样双引号也可以省略。
如果变量与其它字符相连的话,需要使用大括号{ }:
mouth=8
echo "${mouth}-1-2009"
结果将是:
8-1-2009
6.3 显示结果重定向至文件
echo "It is a test" > myfile
6.4 原样输出字符串
若需要原样输出字符串(不进行转义),请使用单引号。例如:
echo '$name\"'
6.5 显示命令执行结果
echo `date`
七 函数
函数可以让我们将一个复杂功能划分成若干模块,让程序结构更加清晰,代码重复利用率更高。像其他编程语言一样,shell 也支持函数。shell 函数必须先定义后使用。
7.1 函数定义
亲爱的读者和支持者们,自动博客加入了打赏功能,陆陆续续收到了各位老铁的打赏。在此,我想由衷地感谢每一位对我们博客的支持和打赏。你们的慷慨与支持,是我们前行的动力与源泉。
日期 | 姓名 | 金额 |
---|---|---|
2023-09-06 | *源 | 19 |
2023-09-11 | *朝科 | 88 |
2023-09-21 | *号 | 5 |
2023-09-16 | *真 | 60 |
2023-10-26 | *通 | 9.9 |
2023-11-04 | *慎 | 0.66 |
2023-11-24 | *恩 | 0.01 |
2023-12-30 | I*B | 1 |
2024-01-28 | *兴 | 20 |
2024-02-01 | QYing | 20 |
2024-02-11 | *督 | 6 |
2024-02-18 | 一*x | 1 |
2024-02-20 | c*l | 18.88 |
2024-01-01 | *I | 5 |
2024-04-08 | *程 | 150 |
2024-04-18 | *超 | 20 |
2024-04-26 | .*V | 30 |
2024-05-08 | D*W | 5 |
2024-05-29 | *辉 | 20 |
2024-05-30 | *雄 | 10 |
2024-06-08 | *: | 10 |
2024-06-23 | 小狮子 | 666 |
2024-06-28 | *s | 6.66 |
2024-06-29 | *炼 | 1 |
2024-06-30 | *! | 1 |
2024-07-08 | *方 | 20 |
2024-07-18 | A*1 | 6.66 |
2024-07-31 | *北 | 12 |
2024-08-13 | *基 | 1 |
2024-08-23 | n*s | 2 |
2024-09-02 | *源 | 50 |
2024-09-04 | *J | 2 |
2024-09-06 | *强 | 8.8 |
2024-09-09 | *波 | 1 |
2024-09-10 | *口 | 1 |
2024-09-10 | *波 | 1 |
2024-09-12 | *波 | 10 |
2024-09-18 | *明 | 1.68 |
2024-09-26 | B*h | 10 |
2024-09-30 | 岁 | 10 |
2024-10-02 | M*i | 1 |
2024-10-14 | *朋 | 10 |
2024-10-22 | *海 | 10 |
2024-10-23 | *南 | 10 |
2024-10-26 | *节 | 6.66 |
2024-10-27 | *o | 5 |
2024-10-28 | W*F | 6.66 |
2024-10-29 | R*n | 6.66 |
2024-11-02 | *球 | 6 |
2024-11-021 | *鑫 | 6.66 |
2024-11-25 | *沙 | 5 |
2024-11-29 | C*n | 2.88 |

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了