bash自定义myecho函数异常:为何输出包含当前目录文件名?
Bash自定义myecho子例程异常问题解析
问题场景
我正在编写一个bash子例程myecho,功能类似echo命令,但会同时在终端显示文本并写入日志文件。但实际运行不符合预期——输出会包含当前目录的文件名。
示例脚本:
#!/bin/bash logfile="/tmp/testif.log" myecho () { echo $*; echo $* >>$logfile; } src="/tmp/testdir" FILE=$src'/afile' if test -f "$FILE"; then myecho '--------------------------------------'; echo '***' $FILE 'exists! ***'; # ^^ 改为myecho会导致输出包含当前目录文件名 else myecho 'Sorry,' $FILE 'does not exist' exit fi
异常现象
将第14行的echo改为myecho后,终端和日志文件输出变为:
-------------------------------------- afile bfile cfile dfile /tmp/testdir/afile exists! afile bfile cfile dfile
而使用原生echo时输出符合预期(仅缺少日志写入功能):
-------------------------------------- /tmp/testdir/afile exists!
问题与解答
问题1:为何test -f的输出会包含当前目录下的所有文件名?
解答:test -f命令本身不会输出任何内容,它仅返回一个退出状态码(0表示文件存在,非0表示不存在)。你看到的当前目录文件名来自Bash的路径扩展(文件名通配)——当未加引号使用*等通配符时,Bash会自动将其替换为当前目录下的所有文件名称,和test -f没有直接关系。
问题2:将第14行从echo改为myecho,为何会导致文件名被包含进输出参数中?
解答:
异常由两个错误共同导致:
- 调用
myecho时的参数写法问题:如果调用时未给包含*的字符串加引号(比如误写成myecho *** $FILE exists! ***而非myecho '***' $FILE 'exists! ***'),Bash会将***识别为通配符,展开成当前目录下的所有文件名,作为参数传递给myecho。 myecho函数内部的参数处理错误:函数中使用echo $*而非带引号的echo "$*",会导致参数被二次拆分和扩展。$*在未加引号时,会将所有参数用空格拼接后进行单词拆分和路径扩展,可能触发意外的通配符展开。
修复方案
修正myecho函数实现
将函数内的$*加上双引号,避免意外扩展:
myecho () { echo "$*"; echo "$*" >> "$logfile"; }
"$*"会将所有参数作为单个完整字符串输出,保留原始空格和特殊字符;- 如果需要保留参数的独立边界,也可以使用
"$@",效果与echo "$@"一致。
修正myecho调用方式
确保调用时的参数正确加引号,避免通配符被展开:
# 推荐写法:将整段文本作为单个参数 myecho "*** $FILE exists! ***"
内容的提问来源于stack exchange,提问作者Wlovewell
相关产品推荐
相关产品推荐

