sudo执行bash脚本时compgen命令找不到的原因及解决方法
问题:sudo执行bash脚本时找不到内置命令compgen
我在目录下有一系列tar包,想选出名称“最大”的(反向排序后的第一个)存入变量,示例文件如下:
goyard@GoYard-BOXER-6404:~/Code/NodejsServer$ ls reports-1.0.0.tgz reports-1.1.0.tgz reports-2.tgz
目标文件是reports-2.tgz。
在bash命令行和直接运行脚本时,用以下命令能正常获取目标文件:
tarball_path=`compgen -G "report*.tgz" | sort -r | head -n 1`
脚本内容:
#!/bin/bash tarball_path=`compgen -G "report*.tgz" | sort -r | head -n 1` echo "tarball_path: ${tarball_path}"
直接运行脚本的输出:
goyard@GoYard-BOXER-6404:~/Code/NodejsServer$ ./get_report_name.sh tarball_path: reports-2.tgz
但用sudo执行脚本时,会报错找不到compgen:
goyard@GoYard-BOXER-6404:~/Code/NodejsServer$ sudo ./get_report_name.sh [sudo] password for goyard: ./get_report_name.sh: 1: compgen: not found tarball_path:
需要使用sudo是因为最终要将tar包解压到Ubuntu主机的/srv目录。
原因分析
- sudo默认会调用系统的
sh(Ubuntu上通常是dash,一款轻量级shell)来执行脚本,而非bash。compgen是bash专属的内置命令,sh环境中没有这个命令,因此会提示找不到。 - 你的脚本shebang写成了
# !/bin/bash(#和!之间有空格),这会导致系统忽略该shebang,直接使用默认shell执行脚本,进一步放大了问题。
解决方法
方法1:修正脚本的shebang
把脚本第一行的# !/bin/bash改为正确的#!/bin/bash(去掉#和!之间的空格)。这样sudo执行时会强制调用bash运行脚本,就能识别compgen命令了。
方法2:强制sudo用bash执行脚本
直接指定用bash运行脚本,命令如下:
sudo bash ./get_report_name.sh
方法3:替换compgen为兼容的外部命令
如果想让脚本在更多shell环境下兼容,可以用通用外部命令替代compgen,比如:
- 用
ls结合版本排序:
tarball_path=$(ls -v report*.tgz | tail -n 1)
- 用
find命令:
tarball_path=$(find . -maxdepth 1 -name "report*.tgz" | sort -r | head -n 1)
这些命令都是外部工具,在sh环境中也能正常运行。
内容的提问来源于stack exchange,提问作者f1fan44
相关产品推荐
相关产品推荐

