Shell脚本执行方法完全指南
1. 基础执行方法
方法1:使用解释器直接执行
# 使用bash解释器
bash script.sh# 使用sh解释器(可能是bash的链接)
sh script.sh# 使用其他shell解释器
zsh script.sh
ksh script.sh
dash script.sh# 指定完整路径
/bin/bash script.sh
/usr/bin/bash script.sh
方法2:添加执行权限后执行
# 添加执行权限
chmod +x script.sh# 然后直接执行
./script.sh# 或者使用绝对路径
/home/user/script.sh
/path/to/script.sh
方法3:使用source或点命令
# 在当前shell环境中执行
source script.sh# 简写形式(功能相同)
. script.sh
2. 各种执行方式的区别
子shell执行 vs 当前shell执行
#!/bin/bash
# demo.sh
export MY_VAR="子shell变量"
echo "MY_VAR: $MY_VAR"
# 测试不同执行方式
echo "=== 方法1: bash script.sh ==="
bash demo.sh
echo "执行后MY_VAR: $MY_VAR" # 空值(变量在子shell中)echo "=== 方法2: ./script.sh ==="
chmod +x demo.sh
./demo.sh
echo "执行后MY_VAR: $MY_VAR" # 空值(变量在子shell中)echo "=== 方法3: source script.sh ==="
source demo.sh
echo "执行后MY_VAR: $MY_VAR" # 有值(变量在当前shell)
执行方式对比表
| 执行方式 | 是否需要执行权限 | 是否创建子shell | 变量是否保持 | 退出状态 |
|---|
bash script.sh | ❌ 不需要 | ✅ 是 | ❌ 不保持 | 脚本最后命令 |
./script.sh | ✅ 需要 | ✅ 是 | ❌ 不保持 | 脚本最后命令 |
source script.sh | ❌ 不需要 | ❌ 否 | ✅ 保持 | 脚本最后命令 |
. script.sh | ❌ 不需要 | ❌ 否 | ✅ 保持 | 脚本最后命令 |
3. 带参数执行
传递参数给脚本
#!/bin/bash
# script_with_args.shecho "脚本名称: $0"
echo "参数个数: $#"
echo "所有参数: $@"for i in $(seq 1 $#); doecho "参数 $i: ${!i}"
done
# 执行带参数的脚本
bash script_with_args.sh arg1 arg2 "arg3 with spaces"./script_with_args.sh apple banana cherrysource script_with_args.sh 参数1 参数2
参数处理示例
#!/bin/bash
# process_args.sh# 处理选项参数
while [[ $# -gt 0 ]]; docase $1 in-v|--verbose)VERBOSE=trueshift;;-f|--file)FILE="$2"shift 2;;-h|--help)echo "用法: $0 [-v] [-f FILE]"exit 0;;*)echo "未知参数: $1"exit 1;;esac
doneecho "详细模式: ${VERBOSE:-false}"
echo "文件: ${FILE:-未指定}"
4. 调试模式执行
各种调试选项
# 显示执行的每一行命令
bash -x script.sh# 显示变量赋值
bash -v script.sh# 组合调试
bash -xv script.sh# 检查语法而不执行
bash -n script.sh# 从指定行开始执行
bash -x --debugger script.sh
脚本内调试设置
#!/bin/bash
# debug_demo.sh# 开启调试
set -x
echo "这一行会被显示"
name="Debug Test"
echo "名字: $name"# 关闭调试
set +x
echo "这一行不会被显示"# 只调试部分代码
(set -xecho "这部分代码会调试"dateset +x
)echo "调试结束"
5. 环境变量控制执行
设置环境变量
# 临时设置环境变量
MY_VAR="value" bash script.sh# 设置多个环境变量
DEBUG=true LOG_LEVEL=info bash script.sh# 清空环境变量执行
env -i bash script.sh # 空环境执行
修改PATH后执行
# 添加自定义路径到PATH
PATH="/my/custom/bin:$PATH" ./script.sh# 使用完整路径避免PATH依赖
/bin/bash /path/to/script.sh
6. 输入输出重定向
重定向标准输入输出
# 输出重定向到文件
bash script.sh > output.txt
bash script.sh >> output.txt # 追加模式# 错误输出重定向
bash script.sh 2> error.log
bash script.sh > output.txt 2>&1 # 合并输出和错误
bash script.sh &> all_output.txt # 合并输出(bash 4.0+)# 输入重定向
bash script.sh < input.txt
echo "input data" | bash script.sh
使用here document
# 直接传递输入数据
bash script.sh << EOF
第一行输入
第二行输入
第三行输入
EOF# 带变量替换的here document
name="John"
age=25
bash script.sh << EOD
姓名: $name
年龄: $age
时间: $(date)
EOD
7. 后台执行和作业控制
后台执行脚本
# 后台执行
bash long_running_script.sh &# 后台执行并忽略挂起信号
nohup bash script.sh &# 后台执行并重定向输出
nohup bash script.sh > output.log 2>&1 &# 使用screen/tmux保持会话
screen -dm bash script.sh
tmux new-session -d bash script.sh
作业控制
# 启动后台作业
bash script.sh &
jobs # 查看后台作业# 将后台作业调到前台
fg %1# 暂停当前作业
Ctrl+Z
bg %1 # 在后台继续运行# 杀死作业
kill %1
8. 定时执行和自动化
使用cron定时执行
# 编辑crontab
crontab -e# 添加定时任务示例
# 每分钟执行
* * * * * /path/to/script.sh# 每天凌晨2点执行
0 2 * * * /path/to/script.sh# 每周一上午9点执行
0 9 * * 1 /path/to/script.sh# 每月1号执行
0 0 1 * * /path/to/script.sh
使用at命令单次执行
# 10分钟后执行
echo "/path/to/script.sh" | at now + 10 minutes# 明天上午9点执行
at 09:00 tomorrow <<< "/path/to/script.sh"# 查看等待的at任务
atq# 删除at任务
atrm 任务编号
9. 条件执行和管道
条件执行
# 只有前一个命令成功才执行
bash script1.sh && bash script2.sh# 只有前一个命令失败才执行
bash script1.sh || bash script2.sh# 复杂条件组合
bash script1.sh && echo "成功" || echo "失败"
管道执行
# 脚本输出作为另一个脚本的输入
bash generator.sh | bash processor.sh# 多个脚本管道连接
bash script1.sh | bash script2.sh | bash script3.sh# 使用tee同时输出到屏幕和文件
bash script.sh | tee output.log
10. 安全执行方式
安全执行最佳实践
# 使用完整路径避免PATH劫持
/bin/bash /path/to/script.sh# 使用sudo以特定用户执行
sudo -u username bash script.sh
sudo -u www-data bash script.sh# 在受限环境中执行
bash --restricted script.sh # 受限模式
bash --norc script.sh # 不读取rc文件
权限控制
# 设置适当的文件权限
chmod 755 script.sh # 所有者可读写执行,其他用户可读执行
chmod 700 script.sh # 只有所有者可读写执行# 设置setuid权限(谨慎使用)
chmod u+s script.sh # 以文件所有者身份执行# 使用acl进行精细控制
setfacl -m u:username:rx script.sh
11. 高级执行技巧
使用exec替换当前进程
#!/bin/bash
# exec_demo.shecho "准备执行exec..."
exec bash -c 'echo "这是exec执行的命令"; sleep 2'
echo "这行不会执行" # 因为exec替换了当前进程
使用trap处理信号
#!/bin/bash
# trap_demo.shcleanup() {echo "收到信号,正在清理..."exit 1
}# 设置信号处理
trap cleanup SIGINT SIGTERMecho "脚本运行中,按Ctrl+C测试信号处理"
sleep 10
echo "正常结束"
使用coproc协程
#!/bin/bash
# coproc_demo.sh# 创建协程
coproc MY_COPROC {while read line; doecho "处理: $line"done
}# 向协程发送数据
echo "数据1" >&${MY_COPROC[1]}
echo "数据2" >&${MY_COPROC[1]}# 从协程读取数据
read -u ${MY_COPROC[0]} result
echo "结果: $result"
12. 实用执行脚本示例
批量执行脚本
#!/bin/bash
# batch_executor.shSCRIPT_DIR="/path/to/scripts"
LOG_DIR="/path/to/logs"# 确保日志目录存在
mkdir -p "$LOG_DIR"# 批量执行所有.sh脚本
for script in "$SCRIPT_DIR"/*.sh; doif [[ -x "$script" ]]; thenscript_name=$(basename "$script")log_file="$LOG_DIR/${script_name}.log"echo "执行: $script_name"bash "$script" > "$log_file" 2>&1if [[ $? -eq 0 ]]; thenecho "✓ $script_name 执行成功"elseecho "✗ $script_name 执行失败"fifi
done
监控脚本执行
#!/bin/bash
# script_monitor.shSCRIPT="$1"
TIMEOUT=300 # 5分钟超时if [[ ! -f "$SCRIPT" ]]; thenecho "错误: 脚本不存在: $SCRIPT"exit 1
fi# 带超时执行
timeout $TIMEOUT bash "$SCRIPT"case $? in0)echo "脚本执行成功";;124)echo "脚本执行超时(超过 ${TIMEOUT}秒)";;*)echo "脚本执行失败,退出码: $?";;
esac
13. 执行方式选择指南
根据场景选择执行方式
| 使用场景 | 推荐执行方式 | 理由 |
|---|
| 临时测试 | bash script.sh | 简单快捷,无需权限 |
| 生产环境 | ./script.sh | 正式规范,权限明确 |
| 配置加载 | source config.sh | 变量在当前shell生效 |
| 调试排错 | bash -x script.sh | 显示执行过程 |
| 定时任务 | crontab | 自动化调度 |
| 后台服务 | nohup script.sh & | 持久化运行 |
| 管道处理 | `script1.sh | script2.sh` |
| 安全执行 | 完整路径执行 | 避免路径劫持 |
最佳实践总结
# 1. 生产环境使用完整路径
/bin/bash /opt/scripts/myscript.sh# 2. 设置适当的执行权限
chmod 750 /opt/scripts/myscript.sh# 3. 使用日志记录
/bin/bash /opt/scripts/myscript.sh >> /var/log/myscript.log 2>&1# 4. 错误处理
/bin/bash /opt/scripts/myscript.sh || echo "执行失败" | mail -s "脚本错误" admin@company.com# 5. 资源限制
timeout 3600 /bin/bash /opt/scripts/myscript.sh
这个完整的指南涵盖了Shell脚本执行的所有主要方法,从基础到高级技巧都有详细说明。根据具体需求选择合适的执行方式非常重要