Bash脚本读取配置文件命令执行报错:'This: command not found'排查修复
问题:Bash脚本执行时功能正常但出现"command not found"错误
问题描述
编写了bash脚本test.sh用于检测端口监听状态,将端口与对应执行命令以键值对形式存入config_file避免硬编码。脚本与配置文件内容如下:
test.sh
#!/bin/bash cat config_file| while read port command; do if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null ; then echo "" > /dev/null else eval "$command" fi done
config_file
80 /bin/bash /home/user/sample_script1.sh 22 /bin/bash /home/user/sample_script2.sh
sample_script1.sh与sample_script2.sh用于通过touch创建示例文件,执行./test.sh时示例文件能正常创建,但终端报错:
./test.sh: line 8: This: command not found
报错原因
- 变量赋值与
eval的风险:read port command仅会将配置行的第二个字段赋值给command?不,实际read的逻辑是最后一个变量接收行尾所有剩余内容,但直接用eval执行包含空格的命令串时,若脚本路径或脚本内容存在特殊解析场景,会触发意外行为。 - 子进程继承标准输入:
cat config_file | while read...的管道结构导致循环在子shell中运行,eval启动的bash子进程会继承管道的标准输入,可能读取config_file剩余行或脚本中的无效内容。 - 脚本本身的语法错误:报错中的
This大概率来自sample_script1.sh或sample_script2.sh中未正确注释的文本行(比如直接写了This is a test而非# This is a test),这行文本被当作命令执行,从而抛出错误。
修复方案
方案1:安全改写脚本(推荐)
用重定向代替管道避免子shell,用数组存储命令替代风险较高的eval:
#!/bin/bash # 从config_file读取内容,避免管道子shell问题 while read -r port cmd_str; do # 将命令字符串拆分为数组,安全处理空格与特殊字符 read -r -a cmd_array <<< "$cmd_str" # 检测端口是否未监听 if ! lsof -Pi :"$port" -sTCP:LISTEN -t >/dev/null; then # 直接执行命令数组,无解析风险 "${cmd_array[@]}" fi done < config_file
方案2:修正现有脚本与依赖文件
- 修复示例脚本的语法错误:确保
sample_script1.sh和sample_script2.sh中所有非命令文本都以#注释,例如:#!/bin/bash # This is a sample script to create test file touch /tmp/sample1.txt - 修改原脚本避免输入继承:执行命令时关闭子进程的标准输入,防止读取管道剩余内容:
#!/bin/bash cat config_file | while read -r port command; do if ! lsof -Pi :"$port" -sTCP:LISTEN -t >/dev/null; then # 关闭标准输入,避免子进程读取管道内容 eval "$command" < /dev/null fi done
关键优化点
- 使用
read -r避免反斜杠字符被意外转义 - 用命令数组替代
eval,彻底避免命令注入与解析错误风险 - 用重定向替代管道,避免子shell带来的变量丢失与输入继承问题
内容的提问来源于stack exchange,提问作者Alfred
相关产品推荐
相关产品推荐

