linux timeout命令
timeout命令 用于在指定的时间后终止命令的执行。它可以为任何命令设置执行时间限制,防止长时间运行或无响应的命令占用系统资源,是编写健壮脚本和自动化任务的重要工具。
命令格式
常用选项
| 选项 |
说明 |
-k, --kill-after=时间 |
在指定时间后发送KILL信号(如果进程仍未终止) |
-s, --signal=信号 |
指定要发送的信号(默认为TERM) |
--preserve-status |
返回子进程的退出状态(即使超时) |
--foreground |
在前台执行命令(当timeout不是从终端运行时) |
-v, --verbose |
详细输出模式 |
--help |
显示帮助信息 |
--version |
显示版本信息 |
时间格式说明
| 格式 |
示例 |
说明 |
| 秒数 |
10 |
10秒 |
| 分钟秒数 |
2m30s |
2分钟30秒 |
| 小时分钟秒数 |
1h5m10s |
1小时5分钟10秒 |
| 带单位缩写 |
5m, 2h, 30s |
分钟、小时、秒 |
| 浮点数 |
0.5, 1.5 |
0.5秒、1.5秒 |
| 无限 |
0 |
不设置超时限制 |
信号说明
SIGTERM (15) - 优雅终止(默认)
SIGKILL (9) - 强制终止
SIGHUP (1) - 挂起信号
SIGINT (2) - 中断信号(Ctrl+C)
- 先用TERM信号,给进程清理机会
- 再用KILL信号,确保进程终止
- 结合
-k选项使用双重保障
- 测试不同信号对应用的影响
使用实例
1. 基本用法:限制命令执行时间
# 限制ping命令最多执行5秒
timeout 5 ping -c 10 google.com
# 限制命令执行1分钟
timeout 1m ./long_running_script.sh
2. 指定发送的信号
# 5秒后发送KILL信号
timeout -s KILL 5 ./script.sh
# 使用信号编号
timeout -s 9 5 ./script.sh # SIGKILL
# 发送SIGHUP信号
timeout -s HUP 30 ./daemon.sh
3. 双重超时保护(-k选项)
# 5秒后发送TERM信号,如果10秒后仍在运行则发送KILL
timeout -k 10 5 ./problematic_command.sh
# 使用不同时间单位
timeout -k 2m 1m ./command.sh # 1分钟后TERM,2分钟后KILL
4. 详细输出模式
# 显示超时执行的详细信息
timeout -v 10 sleep 15
# 输出示例:
# timeout: sending signal TERM to command 'sleep'
# timeout: sending signal KILL to command 'sleep'
5. 保留退出状态
# 即使超时,也返回命令的实际退出状态
timeout --preserve-status 5 ./script.sh
# 在脚本中检查退出状态
timeout --preserve-status 10 ./task.sh
EXIT_STATUS=$?
echo "退出状态: $EXIT_STATUS"
6. 前台执行模式
# 确保命令在前台执行(适用于后台任务)
timeout --foreground 30 ./interactive_tool.sh
7. 复杂命令和管道
# 对管道中的命令设置超时
timeout 5 sh -c 'ls -la | grep "\.txt$"'
# 带参数的命令
timeout 10 find / -name "*.log" -type f
# 多命令组合
timeout 30 bash -c 'command1 && command2 || command3'
8. 在脚本中使用timeout
#!/bin/bash
# 超时执行数据库备份
echo "开始数据库备份..."
if timeout 300 mysqldump -u root -p'password' database > backup.sql; then
echo "备份成功完成"
else
EXIT_STATUS=$?
if [ $EXIT_STATUS -eq 124 ]; then
echo "备份超时(超过5分钟)"
elif [ $EXIT_STATUS -eq 137 ]; then
echo "备份被强制终止(KILL信号)"
else
echo "备份失败,退出状态: $EXIT_STATUS"
fi
fi
9. 网络操作超时控制
# 限制wget下载时间
timeout 30 wget http://example.com/large_file.zip
# 限制curl请求时间
timeout 10 curl -I https://example.com
# 限制ssh连接时间
timeout 60 ssh user@remote-server "ls -la"
10. 无限超时(特殊情况)
# 使用0表示无限超时(不推荐,但有时有用)
timeout 0 ./never_ending_process.sh
实际输出示例
示例1:命令正常完成(未超时)
$ timeout 10 sleep 5
$ echo $?
0
命令在5秒内完成,正常退出,返回状态为0。
示例2:命令超时被终止
$ timeout 5 sleep 10
$ echo $?
124
sleep命令需要10秒,但在5秒时被终止,返回状态124(超时)。
示例3:使用详细模式
$ timeout -v 3 sleep 5
timeout: sending signal TERM to command 'sleep'
timeout: sending signal KILL to command 'sleep'
示例4:双重超时保护
$ timeout -k 3 2 sleep 10
# 2秒后发送TERM信号,3秒后发送KILL信号
$ echo $?
137 # 被KILL信号终止
退出状态码
| 退出码 |
说明 |
常见场景 |
| 0 |
命令在超时前成功完成 |
命令正常执行完毕 |
| 124 |
命令因超时被终止 |
命令执行时间超过限制 |
| 125 |
timeout命令自身失败 |
无效选项、无法执行命令等 |
| 126 |
找到命令但无法执行 |
权限不足、不是可执行文件 |
| 127 |
未找到命令 |
命令不存在或路径错误 |
| 137 |
命令被KILL信号终止 |
使用SIGKILL或-k选项 |
| 其他 |
命令自身的退出状态 |
命令执行失败(使用--preserve-status时) |
实用场景
- 防止脚本无限循环
- 限制资源密集型操作
- 防止内存泄漏进程
- 控制CPU占用时间
- 限制网络请求时间
- 控制下载/上传超时
- 防止网络阻塞
- API调用超时处理
- 定时任务超时控制
- 批处理作业管理
- 系统监控脚本
- 自动化测试
- 备份操作时间限制
- 数据库查询超时
- 服务启动超时控制
- 维护操作时间窗口
实用命令组合
# 监控命令执行时间并记录日志
timeout 60 ./script.sh 2>&1 | tee execution.log
# 循环尝试直到成功(带超时)
for i in {1..3}; do
echo "尝试第 $i 次..."
if timeout 10 ./flaky_command.sh; then
echo "成功!"
break
else
echo "失败,等待重试..."
sleep 5
fi
done
# 并行执行多个命令,每个都有超时限制
(timeout 30 task1.sh) &
(timeout 45 task2.sh) &
(timeout 60 task3.sh) &
wait
# 超时执行并发送通知
if timeout 300 ./backup.sh; then
echo "备份完成" | mail -s "备份成功" admin@example.com
else
EXIT_CODE=$?
echo "备份失败,退出码: $EXIT_CODE" | mail -s "备份失败" admin@example.com
fi
实际脚本示例
示例1:安全的数据库操作脚本
#!/bin/bash
# 安全的数据库维护脚本
DB_HOST="localhost"
DB_USER="admin"
DB_NAME="production_db"
BACKUP_DIR="/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
echo "开始数据库维护..."
# 1. 备份数据库(最多10分钟)
echo "备份数据库..."
if timeout 10m mysqldump -h $DB_HOST -u $DB_USER -p'password' $DB_NAME > \
$BACKUP_DIR/backup_$TIMESTAMP.sql; then
echo "备份成功"
else
BACKUP_EXIT=$?
if [ $BACKUP_EXIT -eq 124 ]; then
echo "错误:备份超时(超过10分钟)"
exit 1
else
echo "错误:备份失败,退出码: $BACKUP_EXIT"
exit 1
fi
fi
# 2. 优化数据库(最多5分钟)
echo "优化数据库..."
if timeout 5m mysql -h $DB_HOST -u $DB_USER -p'password' $DB_NAME \
-e "OPTIMIZE TABLE important_table"; then
echo "优化成功"
else
echo "警告:数据库优化超时或失败,但继续执行..."
fi
# 3. 清理旧数据(最多15分钟)
echo "清理旧数据..."
if timeout 15m mysql -h $DB_HOST -u $DB_USER -p'password' $DB_NAME \
-e "DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 90 DAY)"; then
echo "清理成功"
else
echo "错误:数据清理超时"
exit 1
fi
echo "数据库维护完成!"
示例2:网络服务健康检查脚本
#!/bin/bash
# 网络服务健康检查脚本
SERVICES=(
"http://api.example.com/health:5"
"http://web.example.com:10"
"tcp://db.example.com:3306:3"
"https://auth.example.com:8"
)
echo "=== 服务健康检查 $(date) ==="
for SERVICE in "${SERVICES[@]}"; do
# 解析服务配置
URL=$(echo $SERVICE | cut -d: -f1-2)
TIMEOUT=$(echo $SERVICE | cut -d: -f3)
echo -n "检查 $URL (超时: ${TIMEOUT}s)... "
if [[ $URL == http* ]]; then
# HTTP/HTTPS检查
if timeout $TIMEOUT curl -f -s -o /dev/null $URL; then
echo "✓ 正常"
else
EXIT_CODE=$?
if [ $EXIT_CODE -eq 124 ]; then
echo "✗ 超时"
else
echo "✗ 失败 (退出码: $EXIT_CODE)"
fi
fi
elif [[ $URL == tcp://* ]]; then
# TCP端口检查
HOST_PORT=$(echo $URL | sed 's/tcp:\/\///')
if timeout $TIMEOUT bash -c "cat < /dev/null > /dev/tcp/${HOST_PORT/\// } 2>/dev/null"; then
echo "✓ 正常"
else
echo "✗ 失败"
fi
fi
done
echo "=== 检查完成 ==="
注意事项:
- timeout不能保证立即终止进程,某些进程可能忽略TERM信号
- 使用
-k选项提供双重保护,确保进程最终被终止
- 子进程可能不会被timeout终止,使用进程组或更复杂的方法处理
- 交互式命令可能需要
--foreground选项
- 某些命令(如shell内建命令)可能需要通过
sh -c包装
- 退出状态124表示超时终止,这在脚本中是一个有用的判断条件
- 在生产环境中使用前,充分测试超时时间设置
timeout与其他方法对比
| 方法 |
优点 |
缺点 |
适用场景 |
timeout命令 |
简单直接,功能丰富,支持信号控制 |
可能无法终止所有子进程 |
大多数命令行超时需求 |
| shell内置超时 |
无需外部命令,执行快 |
功能有限,语法复杂 |
简单脚本,兼容性要求高 |
| expect脚本 |
功能强大,支持交互 |
需要额外安装,学习曲线陡 |
复杂的交互式会话 |
| 编程语言(Python等) |
灵活可控,功能完整 |
需要编程知识,依赖运行环境 |
复杂的应用程序逻辑 |
安装timeout
timeout命令通常包含在coreutils软件包中,大多数Linux发行版默认已安装。
# 检查是否已安装
which timeout
timeout --version
# Ubuntu/Debian安装(如果需要)
sudo apt-get install coreutils
# CentOS/RHEL/Fedora安装
sudo yum install coreutils
# 验证安装
timeout --help
相关命令