shell编程中星号(asterisk "*")的坑

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

shell编程中星号(asterisk "*")的坑

wengle   2020-03-11 我要评论
今天分享一个有关shell编程中由通配符引起的问题。 ### 1. 问题代码 cat test.logs ``` 4567890 * ##*************************************## rtyuio**tyuio432 ##*************************************## *rtyuiop*2* yuiop ##*************************************## rtyuiop(3 * 4)iuytr ##*************************************## 8765432 ``` cat script.sh ```bash #!/usr/bin/env bash # 主要功能是将 非##开头 的每行记录写入到文件中,每个文件保存一行记录 logsname=test.logs i=100 while read line do if [[ $line =~ '##' ]];then ((i++)) else echo $line >> $i.txt fi done < "${logsname}" ``` 运行script.sh脚本的结果: ![问题运行结果](https://img2020.cnblogs.com/blog/1938160/202003/1938160-20200310231814094-391135852.png) 从图片上**红框部分**可以看到: > `4567890 *` 被替换为 `4567890 script.sh test.logs` > `rtyuiop(3 * 4)iuytr` 被替换为 `rtyuiop(3 100.txt 101.txt 102.txt script.sh test.logs 4)iuytr` 其他行都正常打印结果,为什么这两行会有问题呢?其他行也有星号,为什么没有被替换呢? ### 2. 原因分析 根据输出结果可以判断出问题的代码:`echo $line >> $i.txt` 首先,介绍一下shell执行脚本的原理: 1. shell读取整个脚本文件,然后从上到下依次执行每一行 2. 假设当前line=4567890 *,当shell执行`echo $line >> $i.txt`时 1. 首先,shell负责替换`$line`的值为:4567890 *,此时代码是:`echo 4567890 * >> $i.txt` 2. 然后,shell在执行echo命令之前,检查命令的参数中是否有**通配符**(PS:此时echo的参数:4567890 *) 3. 很明显,`*`是通配符,shell负责解析通配符,shell会将通配符当作路径或文件名在磁盘上搜寻可能的匹配:若符合要求的匹配存在,则进行替换(路径扩展);否则就将该通配符作为一个普通字符参数传递给echo,然后再由echo进行处理。 4. 解析完通配符后,`*`被替换为`script.sh test.logs`,此时echo命令的参数是:`4567890 script.sh test.logs` 5. 最后,shell执行`echo 4567890 script.sh test.logs`,然后将echo命令执行的结果重定向到文件中。 **Tips:** > 通配符看起来有点像正则表达式,但是它与正则表达式不同的,不能相互混淆。可以把通配符理解为shell能够处理的特殊字符。而且shell的通配符涉及的只有 "*, ?, [], {}" 这几种。 > > 通配符是shell自身支持的,而正则表达式需要相关工具的支持:grep,awk,vi,perl。在文本过滤工具里,都是用正则表达式,比如像awk,sed等,**正则表达式是针对文件的内容**。 **通配符多用于文件名或者路径**上,比如查找find,ls,cp等。 ### 3. 解决方案 根据上面的分析可以知道,`$line`被替换后,通配符`*`再次被shell解析。哪有什么办法可以防止shell解析通配符呢? 1. 使用引用变量:`"$line"`,**在两端加上引号**,这样`"$line"`就变成了一个字符串"4567890 *",而不是两个单独的字符串。 2. 引用变量可防止分词和通配符扩展(也就是shell解析通配符),并且可以防止在变量中包含空格、换行符、通配符等时造成脚本中断。 3. 在shell编程中总是使用**引用变量**的方式,这是一个良好又安全的编码习惯。 ### 4. 参考资料 1. [Reading asterisk character (*) from a file in bash](https://stackoverflow.com/questions/53751907/reading-asterisk-character-from-a-file-in-bash) 2. [When to wrap quotes around a shell variable?](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) 3. [Security implications of forgetting to quote a variable in bash/POSIX shells](https://unix.stackexchange.com/questions/171346/security-implications-of-forgetting-to-quote-a-variable-in-bash-posix-shells) 4. [shellcheck.net-finds bugs in your shell scripts.](https://www.shellcheck.net/) 5. [Linux Shell 通配符、元字符、转义符使用实例介绍](https://www.cnblogs.com/chengmo/archive/2010/10/17/1853344.html)

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们