Bash循环中使用sed时变量无法展开的问题排查
嘿,我帮你排查出几个关键问题,尤其是一个容易忽略的笔误,这应该是导致hole2报错的核心原因!
首先,你脚本里有个致命拼写错误:用sed修改的是config_file.inp,但运行hole时读取的却是configfile.inp(少了下划线)!这意味着hole从头到尾都没用到你修改后的配置文件,自然会读取原来的占位符路径,难怪会报错“Cannot open pdb co-ord input file: $i”。
接下来,我们一步步修复脚本并优化细节:
1. 先修正配置文件名的拼写
把hole < configfile.inp > ...改成hole < config_file.inp > ...,确保读取的是你刚修改好的配置文件。
2. 确保sed能正确展开变量并修改文件
你用双引号包裹sed命令的做法是对的(双引号里的变量会正常展开),但不同系统的sed对-i选项的处理不一样:
- 如果你用的是Linux(GNU sed):
sed -i "..." file可以直接修改原文件 - 如果你用的是macOS/FreeBSD(BSD sed):必须写成
sed -i '' "..." file,否则会把原文件重命名成带后缀的备份,而修改后的内容根本没写到原文件里
我在下面的脚本里加了自动适配系统的逻辑,避免这个坑。另外要注意:你要替换的原始路径是coord /path/to/files/(结尾有斜杠),而$i是完整的文件路径(比如/path/to/files/xxx.pdb),替换后会变成coord /path/to/files/xxx.pdb,这个逻辑是对的,但要确保原始配置里的路径确实是带斜杠的,否则匹配不上。
3. 优化文件名截取逻辑
你原来的var=${i:72}太依赖路径的长度了,万一路径变短或者变长,这个截取就会出错。换成更可靠的方式提取文件名:
- 要完整文件名(比如
xxx.pdb):var=$(basename "$i") - 要去掉
.pdb后缀:var=$(basename "$i" .pdb)
4. 完整修复后的脚本
#!/bin/bash # 切换到hole程序所在目录,切换失败就退出 cd /path/to/hole/dir || { echo "Failed to change directory"; exit 1; } # 开启nullglob,避免没有匹配文件时遍历到"*.pdb"字符串 shopt -s nullglob # 遍历所有pdb文件 for i in /path/to/files/*.pdb; do echo "Processing file: $i" # 提取文件名(更可靠的方式) var=$(basename "$i") # 根据系统适配sed的-i选项 if [[ $(uname) == "Darwin" ]]; then # macOS/BSD sed sed -i '' "s=coord /path/to/files/=coord ${i}=g" config_file.inp else # Linux GNU sed sed -i "s=coord /path/to/files/=coord ${i}=g" config_file.inp fi # 运行hole程序,用正确的配置文件名 hole < config_file.inp > "hole_out_${var}.txt" # 恢复配置文件的原始路径 if [[ $(uname) == "Darwin" ]]; then sed -i '' "s=coord ${i}=coord /path/to/files/=g" config_file.inp else sed -i "s=coord ${i}=coord /path/to/files/=g" config_file.inp fi done
额外调试小技巧
如果还是有问题,可以在替换配置文件后加一行命令,直接查看coord行的内容,确认替换是否成功:
grep coord config_file.inp
这样就能直观看到路径是不是已经变成了目标文件的实际路径,方便排查问题。
内容的提问来源于stack exchange,提问作者Jonah

