shell避坑指南
2022/7/23 5:25:28
本文主要是介绍shell避坑指南,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
约定
- Error:错误写法;
- Bad:是正确写法,但不是推荐写法;
- Good:不仅是正确写法,而且是推荐的写法。
空格避坑
避坑:带有空格的字符串在进行判断操作时要加引号
示例:
str="this is a example" [ -n ${str} ] # Error: 单中括号不能正确处理有空格的情况 [ -n "${str}" ] # Good: 加引号后可以正确处理 [[ -n ${str} ]] # Bad: 双中括号可以正确处理 [[ -n "${str}" ]] # Good: 双中括号虽然可以正确处理,但建议还是加引号
避坑:带有空格的字符串在进行路径操作时要加引号
示例:
mkdir -p test 1/test 2/test3 # Error mkdir -p "test 1"/"test 2"/test3 # Good:建议分开加引号 mkdir -p "test 1/test 2/test3" # Bad cd "test 1"/"test 2"/test3 # Good:建议分开加引号 cd "test 1/test 2/test3" # Bad rm -rf "test 1" # Good rm -rf "test 1"/"test 2" # Good:建议分开加引号 rm -rf "test 1/test 2" # Bad
避坑:带有空格的字符串在进行"/*"路径操作时要加引号
示例:
# 移动 mv "test 1/*" test2 # Error:带有空格的路径,进行/*操作时这样写错误 mv "test 1"/* test2 # Good # 复制 cp "test 1/*" test2 # Error:同理 cp "test 1"/* test2 # Good # 删除 rm -rf "test 1/*" # Error:无法删除`test 1`目录下的内容 rm -rf "test 1"/* # Good
避坑:含有通配符的*的字符串在操作时不可加引号,否则无法正常工作
rm -rf /home/zdy/Ascend-mindxedge*.tar.gz # Good rm -rf /home/zdy/"Ascend-mindxedge*.tar.gz" # Error:无法删除 rm -rf /home/zdy/Ascend-mindxedge* # Good rm -rf /home/zdy/"Ascend-mindxedge*" # Error:无法删除
删除文件避坑
避坑:rm -rf ${path}/*时要确保${path}存在,否则变砖
说明:
如果${path}
为空,则rm -rf ${path}/*
变为rm -rf /*
,会把根目录下的所有文件删完,变砖。
避坑:rm -rf删除目录软连接时不要加末尾斜杠
示例:
# 假定test是指向目录的软连接 rm -rf test # Bad:可以删除test软连接,而不影响真实目录 rm -rf test/ # Error:不会删除test软连接,而是删除test指向目录下的所有文件 rm -f test # Bad:可以删除test软连接,而不影响真实目录 rm -f test/ # Error:无法删除,提示:rm: cannot remove 'test/': Is a directory unlink test # Good
函数调用避坑
避坑:函数只能返回数字,不能返回字符串
示例:
function fun1() { # Good return 1 } function fun2() { # Bad return "1" } function fun3() { # Error return "T" }
说明:
shell不区分数字和字符串,所有内容都是字符串。所以fun1和fun2,return都会解释为返回数字;fun3的"T"
无法解释为数字,错误。
避坑:函数直接返回其它函数需要用$(fun)
function fun1() { return 100 } function fun2() { # Error:「return: fun1: numeric argument required」 return fun1 } function fun3() { # Good:这种写法可以准确的返回fun1的错误码100 return $(fun1) } function fun4() { # Bad fun1 return $? } function fun5() { # Good fun1 local ret=$? # do something ... return ${ret} } function fun6() { # Good:做一层封装,会丢失fun1的错误码, if fun1; then # 如果只想判断fun1是否执行成功而不关心系错误码可用此方法 return 0 else return 1 fi }
避坑:在if中判断函数是否执行成功,不要加$(fun)
# case 1 if myfun arg1 arg2; then # Good:直接调用 echo "function exe success" # do something else echo "fun exe failed" # do something fi # case 2 if $(myfun arg1 arg2); then # Bad:某些情况下会失败 echo "function exe success" # do something else echo "fun exe failed" # do something fi
注意:
shell命令执行成功返回0,失败为非0。因此用if myfun ...
这种方式,必须保证myfun
在执行成功时返回0。
避坑:同时获取函数执行结果和执行状态时,注意local用法避坑
function test() { echo "here" return 1 } # case 1 function main() { local value=$(test) # Error:value能捕获到test的运行结果"here",但$?始终是0,不能捕获到test返回值1 if (($? == 0)); then echo "right" else echo "error" fi } # case 2 function main() { local value value=$(test) # Good:value能捕获到test的运行结果"here",$?也能捕获到test返回值1 if (($? == 0)); then echo "right" else echo "error" fi } # case 3 function main() { value=$(test) # Bad:value能捕获到test的运行结果"here",$?也能捕获到test返回值1,但用的是全局变量,不推荐 if (($? == 0)); then echo "right" else echo "error" fi } main
运算符避坑
避坑:"-eq"的含义不完全等于"=="
# case 1 [[ 1 == 1 ]] # Bad echo $? # 0 # case 2 [[ 01 == 1 ]] # Error echo $? # 1 # case 3 [[ 01 -eq 1 ]] # Good echo $? # 0 # case 4 [[ "01" -eq "1" ]] # Bad echo $? # 0 # case 5 ((01 == 1)) # Good echo $? # 0 # case 6 (("01" == "1")) # Bad echo $? # 0
说明:
- 在shell中一切变量其实都是字符串,并没有数字这个概念,例如:
var=1
和var="1"
,本质上是没有区别的。所以为了进行算数运算,一般都要用expr
、let
等命令;为了进行算数比较,一般要用-eq
、-ne
等比较运算。这些命令和运算符会自动把字符串解释成数字。因此case 3和case 4其实是等价的; ==
既可以用来判断字符串是否相等,又可以用来判断数字是否相等。为了不混淆,如果明确要判断数字,最好用-eq
而不是==
,或者用case 5的方式;如果明确要字符串比较最好用[[ "str1" == "str2" ]]
。对于-ne
、-le
等其它算数运算符原则上类同-eq
。
避坑:字符串空和非空判断
var1= [[ -z" ${var1}" ]] # 结果为0 [[ -n "${var1}" ]] # 结果为1 var2="" [[ -z "${var2}" ]] # 结果为0 [[ -n "${var2}" ]] # 结果为1 var3="ABC" [[ -z "${var3}" ]] # 结果为1 [[ -n "${var3}" ]] # 结果为0
说明:
在shell中var1=
和var2=""
的含义是一样的。因为shell中所有变量都为字符串,而且可加引号也可不加引号。
避坑:变量是否被定义
# var1未被定义 var1= echo ${var1:+word} echo ${var1} # var2未被定义 var2="" echo ${var2:+word} echo ${var2} # var3被定义 var3="ABC" echo ${var3:+word} echo ${var3}
说明:
在shell中var1=
和var2=""
的含义是一样的。因为shell中所有变量都为字符串,而且可加引号也可不加引号。
避坑:shell不支持小数运算,若要进行小数运算需要借助bc或awk
软连接避坑
避坑:当ln的目标是目录时,要防止循环指向
# Error mkdir /root/test_dir # 第一次执行soft_test指向test_dir ln -sf /root/test_dir /root/soft_test # 再次执行会导致test_dir下创建一个这样的软连接:test_dir -> /root/test_dir,导致循环指向 ln -sf /root/test_dir /root/soft_test # Good mkdir /root/test_dir # 第一次执行soft_test指向test_dir ln -sfn /root/test_dir /root/soft_test # 再次执行,不会导致循环指向 ln -sfn /root/test_dir /root/soft_test
原因:
加上-n
参数,会把test_dir看做一个文件,而不是目录,则不会进入test_dir下创建软连接。如果不加-n,则test_dir是目录,创建软连接时会进入这个目录,并在它下边创建软连接。
推荐写法
字符串比较
# 相等 if [[ "${string1}" == "${string2}" ]]; then echo "The two strings are the same" fi # 不等 if [[ "${string1}" != "${string2}" ]]; then echo "The two strings are different" fi # 为空 if [[ -z "${string}" ]]; then echo "empty string" fi # 非空 if [[ -n "${string}" ]]; then echo "string is not empty" fi # ${substring}在${string}中 if [[ "${string}" == *"${substring}"* ]]; then echo "${string} contains: ${substring}" fi # ${substring}在${string}中 if [[ "${string}" =~ "${substring}" ]]; then echo "${string} contains: ${substring}" fi
数值比较
# 相等 if ((int1 == int2)); then echo "equal" fi # 不等 if ((int1 != int2)); then echo "not equal" fi # 大于 if ((int1 > int2)); then echo "greater" fi # 大于等于 if ((int1 >= int2)); then echo "greater or equal" fi # 小于 if ((int1 < int2)); then echo "lesser" fi # 小于等于 if ((int1 <= int2)); then echo "lesser or equal" fi
这篇关于shell避坑指南的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-05-15鸿蒙生态设备数量超8亿台
- 2024-05-13TiDB + ES:转转业财系统亿级数据存储优化实践
- 2024-05-09“2024鸿蒙零基础快速实战-仿抖音App开发(ArkTS版)”实战课程已上线
- 2024-05-09聊聊如何通过arthas-tunnel-server来远程管理所有需要arthas监控的应用
- 2024-05-09log4j2这么配就对了
- 2024-05-09nginx修改Content-Type
- 2024-05-09Redis多数据源,看这篇就够了
- 2024-05-09Google Chrome驱动程序 124.0.6367.62(正式版本)去哪下载?
- 2024-05-09有没有大佬知道这种数据应该怎么抓取呀?
- 2024-05-09这种运行结果里的10.100000001,怎么能最快改成10.1?