ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

shell避坑指南

2022-07-21 15:35:34  阅读:293  来源: 互联网

标签:指南 shell 避坑 echo Good fi test rm


约定

  • 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=1var="1",本质上是没有区别的。所以为了进行算数运算,一般都要用exprlet等命令;为了进行算数比较,一般要用-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,避坑,echo,Good,fi,test,rm
来源: https://www.cnblogs.com/sinicheveen/p/16502101.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有