Shell - 测试

本文介绍了如何进行Shell脚本的调试,包括基本的语法检测、普通调试、中断调试,以及使用高级调试工具bashdb的详细步骤。通过这些方法,可以更有效地定位和解决问题,尤其在处理复杂脚本时更为实用。

任何语编程都有对应的调试工具,如java有Debug、mysql有调试工具、js有调试工具等,shell也不例外
shell的语法检测:相当于java的编译

1. shell语法检测:

sh -n ./test.sh (sh是/bin/sh 是系统提供的可执行脚本)

2. shell的普通调试:

sh -x ./test.sh

如test.sh的内容如下:

#!/bin/bash

echo "welcome to shell debug"
for i in 1 2 3 4 5 6
do
echo $i
done
echo "shell debug is over"

执行sh -x ./test.sh该语句后如下:

  • echo ‘welcome to shell debug’
    welcome to shell debug
  • for i in 1 2 3 4 5 6
  • echo 1
    1
  • for i in 1 2 3 4 5 6
  • echo 2
    2
  • for i in 1 2 3 4 5 6
  • echo 3
    3
  • for i in 1 2 3 4 5 6
  • echo 4
    4
  • for i in 1 2 3 4 5 6
  • echo 5
    5
  • for i in 1 2 3 4 5 6
  • echo 6
    6
  • echo ‘shell debug is over’
    shell debug is over

3. shell的中断调试

在shell中添加一个睡眠,保证可以有时间中断调试 sleep 3 睡眠3秒执行下一个语句

#!/bin/bash

echo "welcome to shell debug"
for i in 1 2 3 4 5 6
do
echo $i
sleep 3 
done
echo "shell debug is over"

在调试过程中可以按Ctrl + Z中断调试,观察结果,然后再按fg键继续调试即可。(先按f在按g键)

4. 使用调试工具-bashdb

【功能】: 类似于GDB的调试工具,可以完成对shell脚本的断点设置,单步执行,变量观察等许多功能
【场合】: 脚本比较大时,通过-x参数调试时已不方便时.
【用法】:
bashdb -c script.sh
bashdb script.sh
bashdb --debugger script.sh
【说明】:该工具默认未安装,当前最新版本为:4.4-0.92,下载目录:http://bashdb.sourceforge.NET/
1). 如果是ubuntu系统,直接用apt-get来安装
apt-get install bashdb
2). 如果是Centos等版本,使用windows下载后,编译,安装,大致步骤如下:
下载:https://sourceforge.net/projects/bashdb/files/bashdb/
[root@hadoop007 ~]# tar -xzvf bashdb-4.4-0.92.tar.gz -C /usr/src
[root@hadoop007 ~]# cd /usr/src/bashdb-4.4-0.92
[root@hadoop007 ~]# ./configure
[root@hadoop007 ~]# make install

【示例】:

vi /home/test1.sh
#!/bin/bash

echo "----------------begin-----------------"
MAX=3
for ((i = 0; i < MAX; i++))
do
   nowdate=`date -d"-$i day" +%Y-%m-%d`
   echo $nowdate
done
echo "----------------end-----------------"

调试命令:
./bashdb --debugger /home/test.sh

[root@hadoop007 bashdb-4.4-0.92]# ./bashdb --debugger /home/test.sh 
bash debugger, bashdb, release 4.4-0.92
Copyright 2002, 2003, 2004, 2006-2012, 2014 Rocky Bernstein
This is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
(/home/test.sh:3):
3:	echo "----------------begin-----------------"  
bashdb<0> n #执行下一条语句
----------------begin-----------------
(/home/test.sh:4):
4:	MAX=3  
bashdb<1> l #列出当前行上下各5行,总共10行
  1:    #!/bin/bash 
  2:    
  3:    echo "----------------begin-----------------"  
  4: => MAX=3  
  5:    for ((i = 0; i < MAX; i++))  
  6:    do  
  7:       nowdate=`date -d"-$i day" +%Y-%m-%d`  
  8:       echo $nowdate  
  9:    done  
 10:    echo "----------------end-----------------"  
bashdb<2> b 7 #在行号为7的行设置断点
Breakpoint 1 set in file /home/test.sh, line 7.
bashdb<3> c #继续运行
Breakpoint 1 hit (1 times).
(/home/test.sh:7):
7:	   nowdate=`date -d"-$i day" +%Y-%m-%d`  
bashdb<4> print $i
0
bashdb<5> n
(/home/test.sh:8):
8:	   echo $nowdate  
bashdb<6> print $nowdate
2017-03-20
bashdb<7> c 10 #单步往下运行10步
One-time breakpoint 2 set in file /home/test.sh, line 10.
2017-03-20
Breakpoint 1 hit (2 times).
(/home/test.sh:7):
7:	   nowdate=`date -d"-$i day" +%Y-%m-%d`  
bashdb<8> finish  #运行到结束
Breakpoint 1 hit (3 times).
(/home/test.sh:7):
7:	   nowdate=`date -d"-$i day" +%Y-%m-%d`  
date -d"-$i day" +%Y-%m-%d
bashdb<(9)> finish
2017-03-19
Breakpoint 1 hit (4 times).
(/home/test.sh:7):
7:	   nowdate=`date -d"-$i day" +%Y-%m-%d`  
bashdb<10> finish
Breakpoint 1 hit (5 times).
(/home/test.sh:7):
7:	   nowdate=`date -d"-$i day" +%Y-%m-%d`  
date -d"-$i day" +%Y-%m-%d
bashdb<(11)> finish
2017-03-18
(/home/test.sh:10):
10:	echo "----------------end-----------------"  
bashdb<12> q  #退出
bashdb: That's all, folks...
<think> 我们正在讨论Makefile中的内容。用户询问了`shell-basename`是什么。在Makefile中,`shell-basename`通常是一个自定义的函数,用于从文件路径中提取基名(即路径的最后一部分)。它可能通过Makefile内置函数实现,也可能通过调用shell命令实现。 由于Makefile本身没有内置的`shell-basename`函数,因此我们需要考虑两种常见的实现方式: 1. 使用Makefile内置函数`notdir`。 2. 通过`shell`函数调用系统的`basename`命令。 下面我将详细解释这两种实现方式,并给出代码示例。 </think> ### `shell-basename` 详解 `shell-basename` 是一个自定义的 Makefile 函数,用于从文件路径中提取最末尾的部分(通常称为"基名")。它模拟了 Unix/Linux 系统中 `basename` 命令的功能,但完全在 Makefile 环境中实现。 #### 典型实现方式 ```makefile # 实现方式1:使用Makefile内置函数 define shell-basename $(notdir $(1)) endef # 实现方式2:通过shell命令实现 define shell-basename $(shell basename $(1)) endef # 实现方式3:带后缀移除功能 define shell-basename $(shell basename $(1) $(2)) endef ``` #### 功能说明 | 参数 | 描述 | |------|------| | `$(1)` | 必需:文件或目录的完整路径 | | `$(2)` | 可选:要移除的文件后缀(仅在方式3中有效) | #### 工作流程 ```mermaid graph TD A[输入路径] --> B{实现方式} B -->|方式1| C[使用notdir函数] B -->|方式2/3| D[调用shell basename命令] C --> E[返回路径最后部分] D --> F[返回路径最后部分] E --> G[输出基名] F --> G ``` #### 示例比较 假设输入路径为 `/home/user/project/src/module.c` | 实现方式 | 调用代码 | 输出结果 | |----------|----------|----------| | 方式1 | `$(call shell-basename,/home/user/project/src/module.c)` | `module.c` | | 方式2 | 同上 | `module.c` | | 方式3 (带后缀) | `$(call shell-basename,/home/user/project/src/module.c,.c)` | `module` | #### 完整使用示例 ```makefile # 定义shell-basename函数(方式1) define shell-basename $(notdir $(1)) endef # 定义带后缀移除的函数(方式3) define shell-basename-with-suffix $(shell basename $(1) $(2)) endef # 测试路径 TEST_PATH := /path/to/example_file.txt # 测试函数 test: @echo "方式1输出: $(call shell-basename,$(TEST_PATH))" @echo "方式3输出: $(call shell-basename-with-suffix,$(TEST_PATH),.txt)" @echo "方式3无后缀: $(call shell-basename-with-suffix,$(TEST_PATH))" ``` **执行结果**: ``` 方式1输出: example_file.txt 方式3输出: example_file 方式3无后缀: example_file.txt ``` ### 技术细节说明 #### 1. `notdir` vs `basename` 命令 | 特性 | `notdir` (Makefile) | `basename` (shell) | |------|---------------------|--------------------| | 依赖 | 纯Makefile实现 | 依赖外部shell环境 | | 性能 | 更快(无进程创建) | 较慢(需创建shell进程) | | 后缀处理 | 无法移除后缀 | 可指定后缀自动移除 | | 路径格式 | 自动处理路径分隔符 | 依赖系统路径格式 | | 跨平台 | 完全跨平台 | 在Windows上可能失效 | #### 2. 路径处理规则 - 移除所有前导目录部分 - 保留最后一部分 - 处理特殊情况: - 路径以斜杠结尾:`/path/dir/` → `dir` - 路径为根目录:`/` → `/` - 空路径:保留为空 #### 3. 后缀处理规则(仅方式3) - 后缀必须完全匹配(区分大小写) - 如果后缀不匹配,返回完整文件名 - 仅移除最后一个后缀: - `file.tar.gz` → `basename file.tar.gz .gz` → `file.tar` - 支持多个后缀: ```makefile define remove-extensions $(call shell-basename,$(1),.c)$(call shell-basename,$(1),.h) endef ``` ### Android构建系统中的应用 在Android NDK构建系统中,典型的模块命名模式: ```makefile LOCAL_PATH := $(call my-dir) define module_base_name $(call shell-basename,$(LOCAL_PATH)) endef LOCAL_MODULE := $(module_base_name)_shared ``` ### 最佳实践建议 1. **跨平台实现**: ```makefile ifeq ($(OS),Windows_NT) define shell-basename $(notdir $(subst \,/,$(1))) endef else define shell-basename $(notdir $(1)) endef endif ``` 2. **带默认后缀移除**: ```makefile define smart-basename $(if $(2), \ $(shell basename $(1) $(2)), \ $(notdir $(1)) \ ) endef ``` 3. **错误处理增强**: ```makefile define safe-basename $(if $(1), \ $(notdir $(1)), \ $(error Invalid path provided) \ ) endef ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值