如何在Shell脚本中禁用*通配符展开?使用noglob仍异常求助
问题分析与解决方案
你的问题核心在于命令替换的执行时机早于set -o noglob生效的时机,导致通配符*还是被展开了。让我一步步拆解原因,再给出修复方案:
为什么set -o noglob没起作用?
看你脚本里的这段代码:
{ set -o noglob sed -e "s/#qry#/$(echo $(cat $infile))/g" <<! ... ! }
Shell的执行逻辑是:在执行分组内的命令之前,会先解析整个命令行中的所有命令替换($(...))和变量展开。也就是说,$(echo $(cat $infile))这部分会在set -o noglob被执行之前就已经完成展开——这时候noglob还没生效,所以echo接收到的*会被当成通配符展开成当前目录的文件列表。
而你在命令行测试set -o noglob后ls *正常,是因为set -o noglob生效后才执行ls *,通配符展开被抑制了,和脚本里的执行顺序完全不同。
修复方案:先抑制通配符再读取SQL内容
我们需要调整顺序,先开启noglob再读取SQL文件内容,同时避免用echo $(cat ...)这种会触发通配符展开的写法。下面是优化后的脚本:
#!/bin/bash if [[ "$1" == "-h" ]] then echo "sqljob [sqlfile] [procnm] [host] [database] [config file]" echo " sqlfile: text file containing an SQL statement" echo " procnm: name that will given to the new, stored procedure" echo " host: hostname of IP address of the database server" echo " database: the procedure will be created here" echo " config file: default configuration file with username and password" exit fi # 给变量加上引号,防止路径含空格时出错 infile="$1" procnm="$2" hn="$3" pn="$4" db="$5" mycfg="$6" # 第一步:开启noglob,读取SQL文件内容到变量(避免*被展开) set -o noglob sql_query=$(cat "$infile") set +o noglob # 用完后关闭,不影响后续命令 # 第二步:构建SQL模板(这里保持变量展开,符合你的需求) sql_template=$(cat <<! drop procedure if exists $procnm; delete from jobs where jobname="$procnm"; insert into jobs set notes="SQL job $procnm", jobname="$procnm", parm_tmpl='int'; delimiter // create procedure $procnm(vqid int) begin call joblogmsg(vqid,0,"$procnm","","Executing #qry#"); drop table if exists ${procnm}_res; create table ${procnm}_res as #qry# end// delimiter ; ! ) # 第三步:用bash内置的字符串替换替换#qry#(比sed更安全,避免SQL里的/等特殊字符干扰) final_sql=${sql_template//\#qry\#/$sql_query} # 最后管道到mysql echo "$final_sql" | mysql --defaults-file="$mycfg" -h "$hn" -P "$pn" "$db"
关键改进点:
- 提前开启
noglob:在读取SQL文件前就开启set -o noglob,确保cat "$infile"输出的*不会被展开。读取完成后关闭noglob,避免影响后续命令。 - 直接读取文件到变量:不用
echo $(cat ...)这种多余的写法,直接把文件内容存到变量里,避免shell拆分参数和通配符展开。 - 用bash内置替换代替sed:避免SQL语句中包含
/、&等sed特殊字符导致替换失败的问题,更稳定可靠。 - 给变量加引号:防止路径或参数含空格时出现意外错误。
这样修改后,SELECT *里的*就会被原样保留,不会被展开成文件列表了。
内容的提问来源于stack exchange,提问作者j4nd3r53n




