ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

【shell编程扫盲系列】结合真实的案例学习如何调试shell脚本?

2021-11-27 14:34:31  阅读:187  来源: 互联网

标签:脚本 shell name get 编程 扫盲 os bash


文章目录


1 问题回顾

在之前的文章 【shell编程扫盲系列】结合真实案例分析“bash shell -e”到底是啥意思? 中,我提到了我遇到一个bash shell -e引发的问题,不瞒大家说,当时我是用echo大法找到出问题的地方,加以修改才解决的。
那么,我们有没有更加优雅的调试方法,解决这类型的问题呢?
本篇文章将会给出答案。

2 shell脚本如何调试

2.1 特别说明

本文中提及的shell脚本,无特殊说明的情况下,指的是bash shell。这里做这个强调的主要原因是,不同的shell的一些基础语法可能有微小的差异,导致在bash shell中可以跑的脚本,但在别的shell上就跑不了。
这种案例可以参见:【Linux Shell】你知道bash shell和dash shell的区别吗?

2.2 shell脚本如何被启动的?

初次看shell脚本的朋友,一定有所疑问为何大部分shell脚本都是#!/bin/bash开头啊?
这里帮你解除疑问:
因为shell脚本说白了就是一系列命令行组成的一个文本文件,由于各式各样的脚本非常多,那么该用哪种脚本的语法去解析这个脚本文件呢?
这里就有2种方式:

  • 通过脚本文件的首行,使用#!/bin/bash指定,像这样就表示它是一个bash shell语法的脚本,应该用/bin/bash去解析;
  • 通过启动的时候,直接用/bin/bash xxx.sh来启动,这样就是手动指定脚本的解析器。

注意:使用方式1的时候,运行脚本只需要./xxx.sh就可以了,但是方式2却不行。

2.3 shell脚本的三个调试选项

从之前的文章中,我们了解了-e选项,其实它还有其他几个跟调试相关的选项,如下所示:

  • -v (verbose 的简称) - 告诉 Shell 读取脚本时显示所有行,激活详细模式。
  • -n (noexec 或 no ecxecution 简称) - 指示 Shell 读取所有命令然而不执行它们,这个选项激活语法检查模式。
  • -x (xtrace 或 execution trace 简称) - 告诉 Shell 在终端显示所有执行的命令和它们的参数。 这个选项是启用 Shell 跟踪模式。

2.4 shell脚本的三种调试方式

2.4.1 在shell脚本的首行加选项

这个就跟-e的方式是一样的,注意加选项的时候,是连着-e起来,比如-evx,而不能这样-e -v -x
这里的选项是可以加多个调试选项。
选项不对报错:

bash_shell_e$ ./test_shell_e.sh 
/bin/bash: - : invalid option

正常示例如下:


#!/bin/shell -evx 的执行结果

/bash_shell_e$ ./test_shell_e.sh 
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac
+ case $- in
+ return
#! /bin/bash -evx

function get_os()
{
        echo "begin to get OS ..."

        os=`uname -a | grep Darwin`
        if [ "$os" != "" ]]; then
                host_os_name=OSX
        else
                os=`uname -a | grep x86_64`
                if [ "$os" != "" ]; then
                        host_os_name=Linux64
                else
                        host_os_name=Linux32
                fi
        fi

        echo "get OS name: $host_os_name"
}

function do_other_things()
{
        echo "do other things ..."
}

get_os
+ get_os
+ echo 'begin to get OS ...'
begin to get OS ...
++ uname -a
++ grep Darwin
+ os=

从这里结果,我们就可以知道,在执行完os=xxx赋值这条语句就退出了,这跟我们使用echo大法得出的结论是一致的。

2.4.2 手动显示shell脚本时加选项

即类似这样: /bin/bash -evx 启动脚本

bash_shell_e$ /bin/bash -vxe test_shell_e.sh 
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac
+ case $- in
+ return
#! /bin/bash -e

function get_os()
{
        echo "begin to get OS ..."

        os=`uname -a | grep Darwin`
        if [ "$os" != "" ]; then
                host_os_name=OSX
        else
                os=`uname -a | grep x86_64`
                if [ "$os" != "" ]; then
                        host_os_name=Linux64
                else
                        host_os_name=Linux32
                fi
        fi

        echo "get OS name: $host_os_name"
}

function do_other_things()
{
        echo "do other things ..."
}

get_os
+ get_os
+ echo 'begin to get OS ...'
begin to get OS ...
++ uname -a
++ grep Darwin
+ os=

注意:当使用命令行传递输入选项后,脚本文件首行的选项就不生效了,这也是我实践过程中才发现的。
如下所示: 我的脚本首行是指定了-e的,但是它依然跑成功了,因为我使用-x启动,没有带-e

bash_shell_e$ /bin/bash -x test_shell_e.sh    
+ case $- in
+ return
+ get_os
+ echo 'begin to get OS ...'
begin to get OS ...
++ uname -a
++ grep Darwin
+ os=
+ '[' '' '!=' '' ']'
++ uname -a
++ grep x86_64
+ os='Linux ubuntu 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux'
+ '[' 'Linux ubuntu 5.4.0-65-generic #73-Ubuntu SMP Mon Jan 18 17:25:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux' '!=' '' ']'
+ host_os_name=Linux64
+ echo 'get OS name: Linux64'
get OS name: Linux64
+ do_other_things
+ echo 'do other things ...'
do other things ...
+ exit 0

2.4.3 通过set命令设置调试选项

使用方法如下,它可以在脚本中调试任意一个函数,用法非常灵活

#! /bin/bash -e

function get_os()
{
	echo "begin to get OS ..."

 	os=`uname -a | grep Darwin`
	if [ "$os" != "" ]; then
		host_os_name=OSX
	else
		os=`uname -a | grep x86_64`
		if [ "$os" != "" ]; then
			host_os_name=Linux64
		else
			host_os_name=Linux32
		fi
	fi

	echo "get OS name: $host_os_name"
}

function do_other_things()
{	
	echo "do other things ..."
}

# open debug option
set -xv

get_os

# close debug option
set +xv

# re-open debug option
set -xv

do_other_things

# close debug option
set +xv

exit 0

增加这些调试之后,运行结果如下:

bash_shell_e$ ./test_shell_e_debug.sh 

get_os
+ get_os
+ echo 'begin to get OS ...'
begin to get OS ...
++ uname -a
++ grep Darwin
+ os=

从这个输出,我们也可以看到在执行完ox=xxx赋值之后,脚本就停止运行,退出了,这跟我们之前的分析是一致的。
这个方法对于调试shell的函数非常有用,值得注意的是,set -xxx需要加在执行部分,而不是声明部分。

3 经验总结

  • 调试shell脚本有3个选项,-x -n -v 用法各异,灵活使用;
  • 调试shell脚本的方式也有3种,选用自己熟悉且方便的一种即可,高效排查问题。

4 更多分享

本项目的所有测试代码和编译脚本,均可以在我的github仓库01workstation中找到,欢迎指正问题。

同时也非常欢迎关注我的RT-Thread主页、CSDN主页和专栏:

【RT-Thread主页:架构师李肯】

【CSDN主页:http://yyds.recan-li.cn】

【C/C++语言编程专栏】

【GCC专栏】

【信息安全专栏】

【RT-Thread开发笔记】

【freeRTOS开发笔记】

有问题的话,可以跟我讨论,知无不答,谢谢大家。

标签:脚本,shell,name,get,编程,扫盲,os,bash
来源: https://blog.csdn.net/szullc/article/details/121576692

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有