精华内容
下载资源
问答
  • 1、函数定义 linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。Shell 函数定义的语法格式如下: [function] funname [()]{ 函数体 [return int;] } 格式1: 简化写法,不写 function 关键字: ...

    分享知识 传递快乐

     

    1、函数定义

    linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。Shell 函数定义的语法格式如下:

    [function] funname [()]{
        函数体
        [return int;]
    }

    格式1:

    简化写法,不写 function 关键字:

    函数名(){
        函数体
    }

    格式2:

    这是标准写法,也推荐大家使用的写法:

    function 函数名(){
    	命令序列
    }

    这样方便做到一看就懂。

    格式3:

    如果写了 function 关键字,也可以省略函数名后面的小括号:

    function 函数名{
    	命令序列
    }


    说明:

    • function 是 Shell 中的关键字,专门用来定义函数;可以带function funname () 定义,也可以直接funname () 定义,不带任何参数;
    • funname 是函数名;
    • 函数体 是函数要执行的代码,也就是一组语句;
    • return int 表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写,如果不加,将以最后一条命令运行结果,作为返回值。

     

    2、函数变量

    Shell 函数的变量不像其它语言中需要在变量前定义变量类型什么的,更没有结果符号等。语法:

    num=1

    变量作用域

    局部变量:作用域是函数的生命周期;在函数结束时被自动销毁。定义局部变量的方法:

    local VAR=VALUE

    本地变量:作用域是运行脚本的shell进程的生命周期;因此,其作用范围为当前shell

    示例一:

    #!/bin/bash
    
    #在函数外定义本地变量
    var="Hello,World"
    
    function show() {
        #在函数内改变变量内容
        var="Hi,var is changed"
    }
    echo "$var"
    show
    echo "$var"

    输出结果:

    [guest@localhost shell]$ ./tempsh.sh
    Hello,World
    Hi,var is changed

    结果显示在调用函数后,原有的本地变量var被替换了。还好这个变量并不是重要的部分,想想若是PATH被替换了,那么这个函数的罪过就大了。因此我们如何即调用函数中定义的变量同时又不对本地变量造成任何影响呢?局部变量的出现就是为了解决这个问题。

    下面看看在使用了局部变量后的效果。

    #!/bin/bash
    #在函数外定义本地变量
    var="Hello,World"
    
    function show() {
        #在函数内改变变量内容
        local var="Hi,var is changed"
        echo "$var"
    }
    echo "$var"
    show
    echo "$var"

    输出结果

    [guest@localhost shell]$ ./tempsh.sh
    Hello,World
    Hi,var is changed
    Hello,World

    该实验结果说明,使用局部变量后,函数体中出现的变量作用范围只存在于当前函数生命周期。

     

    3、函数调用

    定义函数的代码段不会自动执行,而是在调用时执行;在函数定义好后,用户可以在shell 中直接调用,调用时不用带上();调用 Shell 函数时可以给它传递参数,也可以不传递。如果不传递参数,直接给出函数名字即可。

    示例一:

    #!/bin/bash
    
    # 函数定义
    function show(){
        echo "Hello word"
    }
    
    # 函数调用
    show

    输出结果:

    Hello word

    函数调用成功。上边的例子是把函数把在脚本上边,那么如果放函数放在下边会怎样呢?

    无非就两种结果:1成功,2失败

    下面我们举例测试一下:

    示例二:

    #!/bin/bash
    
    # 函数调用
    show
    
    #函数定义
    function show(){
        echo "Hello word"
    }

    输出结果:

    ./tempsh.sh:行4: show: 未找到命令

    系统报错,为啥?为什么会报错呢?

    首先,脚本的执行顺序是从上到下顺序执行的,因此会先执行show,通过定义的环境变量$PATH定义的路径找不到show对应的命令因此报“show:未找到命令”。

    我们在终端命令行中输错命令报错也是这个原因。终端命令行默认会将最左面输入的内容当做命令,因此若是错误的命令,不是命令的命令等内容都会报错。

    通过上面的对比,我们至少知道函数的调用若是在同一个脚本中,调用操作需要在定义的函数后面。

     

    4、函数传参

    函数传参调用语法:

    函数名 参数1 参数2 ....

    如果传递参数,那么多个参数之间以空格分隔:

    funname param1 param2 param3

    不管是哪种形式,函数名字后面都不需要带括号。和其它编程语言不同的是,Shell 函数在定义时不能指明参数,但是在调用时却可以传递参数,并且给它传递什么参数它就接收什么参数。

    在Shell中,调用函数时可以向其传递参数。在函数体内部,函数中的变量均为全局变量,没有局部变量,若使用局部变量需要在变量前加上 local,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数....

    示例:

    #!/bin/bash
    
    function show(){
        echo "第一个参数为 $1 !"
        echo "第二个参数为 $2 !"
        echo "第十个参数为 $10 !"
        echo "第十个参数为 ${10} !"
        echo "第十一个参数为 ${11} !"
        echo "参数总数有 $# 个!"
        echo "作为一个字符串输出所有参数 $* !"
    }
    
    show 0 1 2 3 4 5 6 7 8 9 10 11

    输出结果:

    第一个参数为 0 
    第二个参数为 1 
    第十个参数为 10 
    第十个参数为 9 
    第十一个参数为 10 
    参数总数有 12 个
    作为一个字符串输出所有参数 0 1 2 3 4 5 6 7 8 9 10 11 

    注意:$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

    另外,还有几个特殊字符用来处理参数:

    参数处理说明
    $#传递到脚本的参数个数
    $*以一个单字符串显示所有向脚本传递的参数
    $$脚本运行的当前进程ID号
    $!后台运行的最后一个进程的ID号
    $@与$*相同,但是使用时加引号,并在引号中返回每个参数。
    $-显示Shell使用的当前选项,与set命令功能相同。
    $?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

     

    5、函数返回值

    退出状态码

    在介绍函数返回值前先了解一下跟函数返回值有关的状态退出码。

    Shell 中运行的每个命令都使用退出状态码(exit status)来告诉shell它完成了处理。退出状态码是一个0-255之间的整数值,在命令结束运行时由命令传给shell。你可以捕获这个值并在脚本中使用。

    如何查看退出状态码呢?

    Linux提供了 $? 专属变量来保存上个执行的命令的退出状态码。你必须在你要查看的命令之后马上查看或使用 $? 变量。它的值会变成Shell中执行的最后一条命令的退出状态码。

    退出状态码大体分两种:

    • 一种是命令正确执行的状态码,该状态码为:0
    • 一种是命令错误执行的状态码,为1-255

     Linux退出状态码

    状态码描述
    0命令成功结束
    1通用未知错误
    2误用shell命令
    126命令不可执行
    127没找到命令
    128无效退出参数
    128+xLinux信号x的严重错误
    130命令通过Ctrl+C终止
    255退出状态码越界

    在脚本中也可以指定退出状态码的值,通过命令exit实现。

    状态码取值范围为0-255,如果在指定的状态码大于255,那么shell会通过模(模就是256)运算得到相应的退出状态码。

    示例一:

    成功的

    #!/bin/bash
    
    # 函数定义
    function show(){
        echo $(date +%Y%m%d)
    }
    show
    echo $?

    输出结果:

    0

    示例二:

    失败的

    #!/bin/bash
    
    SYS_DATE=$(date +%Y%m%d)
    
    echo $SYS_DATE
    
    # 函数定义
    function show(){
        log=`lt`
    	echo log
    }
    show
    echo $?

    输出结果:

    [guest@localhost shell]$ ./tempsh.sh 
    20191123
    ./tempsh.sh:行10: lt: 未找到命令
    log
    0
    

    这次,由于函数最后一行命令正确执行,函数的退出状态码就是0,尽管函数中有一条命令没有成功运行。

    使用函数的默认退出状态码是很危险的,幸运的是return命令可以解决这个问题。

    示例:

    #!/bin/bash
    
    SYS_DATE=$(date +%Y%m%d)
    
    echo $SYS_DATE
    
    # 函数定义
    function show(){
        log=`lt`
    	echo log
    	return 2
    }
    show
    echo $?

    输出结果:

    [guest@localhost shell]$ ./tempsh.sh 
    20191123
    ./tempsh.sh:行10: lt: 未找到命令
    
    2
    

    还是使用相同的函数,在函数最后加上return指定的状态码2。

     

    函数返回值

    Shell函数返回值,常用的两种方式:return、echo。

     

    1)return 语句

    Shell函数的返回值,可以和其他语言的返回值一样,通过return语句返回,return只能用来返回整数值。

    示例一:

    #!/bin/bash
    
    function getResultFun(){
        echo "这是我的第一个 shell 函数!"
        return `expr 1 + 1`
    }
    
    getResultFun
    echo $?

    输出结果:

    这是我的第一个 shell 函数!
    2

    Shell 函数返回值只能是整形数值,一般是用来表示函数执行成功与否的,0表示成功,其他值表示失败。用函数返回值来返回函数执行结果是不合适的。如果return某个计算结果,比如一个字符串,往往会得到错误提示:“numeric argument required”。

    如果一定要让函数返回一个或多个值,可以定义全局变量,函数将计算结果赋给全局变量,然后脚本中其他地方通过访问全局变量,就可以获得那个函数“返回”的一个或多个执行结果了。

    示例:

    #!/bin/sh
    
    function getStr(){
    	return "string"
    }
    
    getStr
    echo $?

    输出如下:

    ./test.sh: line 5: return: string: numeric argument required
    255

    可以看到已经提示要求return 整数类型,真实返回值是255。当面对这种问题怎么解决呢?

    别急,断续看下去你就会找到你想要的答案了。

     

    2)echo 语句

    echo是通过输出到标准输出返回,可以返回任何类型的数据。

    示例:

    #!/bin/sh
    
    function test()  {
    	echo "arg1 = $1"
    	if [ $1 = "1" ] ;then
    		echo "1"
    	else
    		echo "0"
    	fi
    }
    
    echo
    echo "test 1"
    test 1
    
    echo
    echo "test 0"
    test 0
    
    echo
    echo "test 2"
    test 2

    输出结果:

    test 1
    arg1 = 1
    1
    
    test 0
    arg1 = 0
    0
    
    test 2
    arg1 = 2
    0

     

    3)函数返回值总结

    学习了上面的函数返回值的操作后我们下面做个知识总结,我们先看一用例:

    #!/bin/bash
    
    function getResultFun(){
        echo "这是我的第一个 shell 函数!"
        return `expr 1 + 1`
    }
    
    getResultFun
    echo $?
    
    function getResultFun2(){
     echo "这是我的第二个 shell 函数!"
     expr 1 + 1
    }
    
    getResultFun2
    echo $?
    
    getResultFun
    echo 在这里插入命令!
    echo $?

    输出结果:

    这是我的第一个 shell 函数!
    2
    这是我的第二个 shell 函数!
    2
    0
    这是我的第一个 shell 函数!
    在这里插入命令!
    0

    这是为什么?

    因为调用 getResultFun2 后,函数最后一条命令 expr 1 + 1 得到的返回值($?值)为 0,意思是这个命令没有出错。所有的命令的返回值仅表示其是否出错,而不会有其他有含义的结果。

    第二次调用 getResultFun 后,没有立即查看 $? 的值,而是先插入了一条别的 echo 命令,最后再查看 $? 的值得到的是 0,也就是上一条 echo 命令的结果,而 getResultFun 的返回值被覆盖了。下面这个测试,连续使用两次 echo $?,得到的结果不同,更为直观:

    #!/bin/bash
    
    function getResult(){
        echo "这是我的第一个 shell 函数!"
        return `expr 1 + 1`
    }
    
    getResult
    echo $?
    echo $?

    输出结果:

    这是我的第一个 shell 函数!
    2
    0

     

    6、获取函数返回值

    我们上面谈到了函数定义、传参、调用、返回结果,那我们如果得到返回结果呢?上面也谈到了一种获取返回结果的方法 $? ,难道只有这一种方式吗?答案肯定不止。

    示例一:

    用 $? 获取返回值,上面已有介绍,在这里就不做介绍了。

    示例二:

    #!/bin/sh
    
    function getStr(){
    	return "string"
    }
    
    #方法一
    echo `getStr` 
    
    #方法二
    echo $(getStr) 

    两种写法的原理一样的,将getStr当成命令执行,然后获取其标准输出。

    示例三:函数传参

    #!/bin/bash
    
    #创建目录
    function createDir(){
    	if [ ! -d $1 ]; then
    		mkdir -p $1
    	fi
    }
    
    DIR="temp/"
    # 两者二先一
    #$(createDir $DIR)
    $(createDir "temp/")

    函数返回值获取的方法总结:

    • 用变量接收函数返回值,函数用echo等标准输出将要返回的东西打印出来。
    • 用 $? 来接收函数的执行状态,但是 $? 要紧跟在函数调用处的后面。

     

     

     

     

     

     

     

     

     

     

    ———————————
    相互学习,共同进步
    如有不足请留言指正

    展开全文
  • 对于中断函数返回值的分析

    万次阅读 2012-10-31 09:35:14
    在一次自己编写中断处理函数的时候,没有写函数返回值,make的时候是正常编译通过的,但是在运行过程中就报错了,于是对中断函数返回值进行了一定的了解,总结一下。 1.中断的注册与释放: 实现中断注册...

    =============================================================================================

    原文地址:http://os.zju.edu.cn/bbs/zjuos2011/?q=node/1234

    讲述了:IRQ_HANDLED 

    =============================================================================================

    在一次自己编写中断处理函数的时候,没有写函数的返回值,make的时候是正常编译通过的,但是在运行过程中就报错了,于是对中断函数的返回值进行了一定的了解,总结一下。

    1.中断的注册与释放:
    实现中断注册接口:

    /*------------------------------------------------------------------------------------*/
    int request_irq(unsigned int irq,
    irqreturn_t (*handler)(int, void *,
    struct pt_regs *),
    unsigned long flags,
    const char *dev_name,
    void *dev_id);
    
    void free_irq(unsigned int irq, void *dev_id);
    /*------------------------------------------------------------------------------------*/

    其中函数中的参数说明
    unsigned int irq:所要注册的中断号
    irqreturn_t (*handler)(int, void *, struct pt_regs *):中断服务程序的入口地址。
    unsigned long flags:与中断管理有关的位掩码选项,有三组值:
    (1). SA_INTERRUPT :快速中断处理程序,当使用它的是后处理器上所有的其他中断都被禁用。
    (2). SA_SHIRQ :该中断是在设备之间可共享的
    (3). SA_SAMPLE_RANDOM:这个位表示产生的中断能够有贡献给 /dev/random和 /dev/urandom 使用的加密池。
    const char *dev_name:设备描述,表示那一个设备在使用这个中断。

    void *dev_id:用作共享中断线的指针。它是一个独特的标识, 用在当释放中断线时以及可能还被驱动用来指向它自己的私有数据区(来标识哪个设备在中断) 。这个参数在真正的驱动程序中一般是指向设备数据结构的指针。在调用中断处理程序的时候它就会传递给中断处理程序的void *dev_id。(这是我的理解)如果中断没有被共享, dev_id 可以设置为 NULL, 但是使用这个项指向设备结构不管如何是个好主意。我们将在"实现一个处理"一节中看到 dev_id 的一个实际应用。

    中断号的查看可以使用下面的命令:“cat /proc/interrupts”。

    /proc/stat 记录了几个关于系统活动的低级统计量, 包括(但是不限于)自系统启动以来收到的中断数。stat 的每一行以一个文本字串开始, 是该行的关键词。
    第一个数是所有中断的总数, 而其他每一个代表一个单个 IRQ 线, 从中断 0 开始,所有的计数跨系统中所有处理器而汇总的。这个快照显示, 中断号 4 已使用 1 次, 尽管当前没有安装处理。

    以下是一个统计中断时间间隔的中断服务程序。

    /*------------------------------------------------------------------------------------*/
    irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs)
    {
    static long mytime=0;
    static int i=0;
    struct net_device *dev=(struct net_device *)dev_id;
    
    if(i==0){
    mytime=jiffies;
    }else
    if(iname,dev->irq);
    }
    
    i++;
    return IRQ_HANDLED;
    }
    /*------------------------------------------------------------------------------------*/

    这个函数实现的只是对两次发生中断的时间间隔的统计,时间单位是毫秒

    函数参数说明:
    int irq :在这里很明显传递过来的是中断号
    void *dev_id :这个传递来的是设备的id号,可以根据这个设备id号得到相应设备的数据结构,进而的到相应设备的信息和相关数据。下面以提取网路数据为例来说明一下。
    struct net_device *dev=( struct net_device *)dev_id; (这里的dev_id的值是注册中断的时候宏传递过来的,是注册中断函数的最后一个参数)
    在这之后就可以用dev->name; dev->irq;等得到网络设备的信息了,当然提取ip数据报还得进行一些其它的工作。
    struct pt_regs *regs :它指向一个数据结构,此结构保存的是中断之前处理器的寄存器和状态。主要用在程序调试。
    关于中断处理函数的返回值:中断程序的返回值是一个特殊类型—irqreturn_t。但是中断程序的返回值却只有两个—IRQ_NONE和IRQ_HANDLED。

    /* irqreturn.h */

    #ifndef _LINUX_IRQRETURN_H

    #define _LINUX_IRQRETURN_H

    typedef int irqreturn_t;

    /*For 2.4.x compatibility, 2.4.x can use
    * typedef void irqreturn_t;
    * #define IRQ_NONE
    * #define IRQ_HANDLED
    * #define IRQ_RETVAL(x)
    ...
    * To mix old-style and new-style irq handler returns.
    * IRQ_NONE means we didn't handle it.
    * 中断程序接收到中断信号后发现这并不是注册时指定的中断原发出的中断信号.
    *此时返回次值
    * IRQ_HANDLED means that we did have a valid interrupt and handled it.
    * 接收到了准确的中断信号,并且作了相应正确的处理
    * IRQ_RETVAL(x) selects on the two depending on x being non-zero (for handled)
    */

    #define IRQ_NONE (0)

    #define IRQ_HANDLED (1)

    #define IRQ_RETVAL(x) ((x) != 0) //这个宏只是返回0或非0

    #endif


    展开全文
  • Linux system函数返回值

    千次阅读 2013-07-11 12:00:58
    例: [cpp] view plaincopy ...(1)system返回值:指调用system函数后的返回值,比如上例中status为system返回值 (2)shell返回值:指system所调用的shell命令的返回值,比如上例中
    例:
    [cpp]  view plain copy
    1. status = system("./test.sh");  
    文章转载来自于:http://blog.chinaunix.net/uid-24774106-id-3048281.html?page=3

    1、先统一两个说法:
    (1)system返回值:指调用system函数后的返回值,比如上例中status为system返回值
    (2)shell返回值:指system所调用的shell命令的返回值,比如上例中,test.sh中返回的值为shell返回值。

    2、如何正确判断test.sh是否正确执行?
    仅判断status是否==0?或者仅判断status是否!=-1? 

    都错!

    3、man中对于system的说明

    RETURN VALUE
           The value returned is -1 on error (e.g.  fork() failed), and the return
           status  of  the command otherwise.  This latter return status is in the
           format specified in wait(2).  Thus, the exit code of the  command  will
           be  WEXITSTATUS(status).   In  case  /bin/sh could not be executed, the
           exit status will be that of a command that does exit(127)
    .
    看得很晕吧?

    system函数对返回值的处理,涉及3个阶段:
    阶段1:创建子进程等准备工作。如果失败,返回-1。
    阶段2:调用/bin/sh拉起shell脚本,如果拉起失败或者shell未正常执行结束(参见备注1),原因值被写入到status的低8~15比特位中。system的man中只说明了会写了127这个值,但实测发现还会写126等值。
    阶段3:如果shell脚本正常执行结束,将shell返回值填到status的低8~15比特位中。
    备注1:
    只要能够调用到/bin/sh,并且执行shell过程中没有被其他信号异常中断,都算正常结束。
    比如:不管shell脚本中返回什么原因值,是0还是非0,都算正常执行结束。即使shell脚本不存在或没有执行权限,也都算正常执行结束。
    如果shell脚本执行过程中被强制kill掉等情况则算异常结束。

    如何判断阶段2中,shell脚本是否正常执行结束呢?系统提供了宏:WIFEXITED(status)。如果WIFEXITED(status)为真,则说明正常结束。
    如何取得阶段3中的shell返回值?你可以直接通过右移8bit来实现,但安全的做法是使用系统提供的宏:WEXITSTATUS(status)。


    由于我们一般在shell脚本中会通过返回值判断本脚本是否正常执行,如果成功返回0,失败返回正数。
    所以综上,判断一个system函数调用shell脚本是否正常结束的方法应该是如下3个条件同时成立:
    (1)-1 != status
    (2)WIFEXITED(status)为真
    (3)0 == WEXITSTATUS(status)

    注意:
    根据以上分析,当shell脚本不存在、没有执行权限等场景下时,以上前2个条件仍会成立,此时WEXITSTATUS(status)为127,126等数值。
    所以,我们在shell脚本中不能将127,126等数值定义为返回值,否则无法区分中是shell的返回值,还是调用shell脚本异常的原因值。shell脚本中的返回值最好多1开始递增。

    判断shell脚本正常执行结束的健全代码如下:

    [cpp]  view plain copy
    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <sys/wait.h>  
    4. #include <sys/types.h>  
    5.   
    6. int main()  
    7. {  
    8.     pid_t status;  
    9.   
    10.   
    11.     status = system("./test.sh");  
    12.   
    13.     if (-1 == status)  
    14.     {  
    15.         printf("system error!");  
    16.     }  
    17.     else  
    18.     {  
    19.         printf("exit status value = [0x%x]\n", status);  
    20.   
    21.         if (WIFEXITED(status))  
    22.         {  
    23.             if (0 == WEXITSTATUS(status))  
    24.             {  
    25.                 printf("run shell script successfully.\n");  
    26.             }  
    27.             else  
    28.             {  
    29.                 printf("run shell script fail, script exit code: %d\n", WEXITSTATUS(status));  
    30.             }  
    31.         }  
    32.         else  
    33.         {  
    34.             printf("exit status = [%d]\n", WEXITSTATUS(status));  
    35.         }  
    36.     }  
    37.   
    38.     return 0;  
    39. }  

    WIFEXITED(stat_val) Evaluates to a non-zero value if status
    was returned for a child process that
    terminated normally.

    WEXITSTATUS(stat_val) If the value of WIFEXITED(stat_val) is
    non-zero, this macro evaluates to the
    low-order 8 bits of the status argument
    that the child process passed to _exit()
    or exit(), or the value the child
    process returned from main().



    1. #include <stdlib.h>

    2. int system(const char *command);
         system的作用是在shell终端执行command。简单的说就是在C中执行system("ls")这行代码的含义就相当于在shell执行ls一样。这么说还是比较笼统,下面详细描述之:

        system是个综合的操作,分解开来看就是相当于执行了
    1 fork  生成一个子进程。
    2 在子进程执行 execl("/bin/sh","sh","-c" command,(char*)0);
    3 waitpid

    下面进入正题,返回值:
    1 如果fork失败了,或者waitpid返回除了EINTR之外的错误,system返回 -1;
    2 execl执行失败,其返回值如同shell执行了"exit(127)" 一样。
    3 如果上述三步都执行成功,那么,system返回值是shell的终止状态。


    上面这些话是APUE的,很抽象,很不具体,很笼统,我现在结合手册和代码解释一下。

    手册中有这么一段话:
    1. The value returned is -1 on error (e.g. fork(2) failed), and the return status of the command otherwise. This latter  return status is in the format specified in wait(2). Thus, the exit code of the command will be WEXITSTATUS(status). In case /bin/sh could not be executed, the exit status will be that of a command that does
    2.  exit(127).
    1 如果/bin/sh拉起shell命令失败,或者是shell命令没有正常执行 (比如命令根本就是非法的命令),那么,将原因填入status的8~15位。
      手册中也说如果命令执行不起来,那么相当于执行exit
    1. libin@libin:~/program/C/Linux/system$ ./tsys "nosuchcmd"
    2. sh: nosuchcmd: not found
    3. status = 32512
    4. normal termination,exit status = 127
    我们看到了,nosuchcmd不是shell支持的命令,所以,shell命令返回了127,对于system函数,返回值为 127*256 = 32512;因为shell的返回值是 system返回值的8~15位。

    2  如果shell顺利执行完毕,那么将shell的返回值填到system返回值的8~15位。
     这里需要强调以下,所谓顺利执行完毕,并不是说,命令command执行成功,而是指  /bin/sh顺利调用,执行期间没有被信号异常终止,这都算是顺利执行完毕。
      
    看下面的例子:

    1. libin@libin:~/program/C/Linux/system$ ./tsys "ls /noexisted"
    2. ls: 无法访问/noexisted: 没有那个文件或目录
    3. status = 512
    4. normal termination,exit status = 2

    5. libin@libin:~/program/C/Linux/system$ ls /noexist
    6. ls: 无法访问/noexist: 没有那个文件或目录
    7. libin@libin:~/program/C/Linux/system$ echo $?
    8. 2
    9. libin@libin:~/program/C/Linux/system$ 
        我们看到了,虽然/noexist文件并不存在,ls这条命令执行出了错,但是仍然属于shell顺利执行完毕。 ls /noexist的错误吗是2,所以,system函数的返回值为 2*256 = 512.

        各位可能比较感兴趣的是,如果我知道system的返回值,如何知道我的命令的返回值呢?手册中有这么一句话:
    1. Thus, the exit code of the command will be WEXITSTATUS(status)
        看到了WEXITSTATUS(status),就是command的返回值。当然前提条件是shell命令顺利执行完毕。即
    1. WIFEXITED(status) ! =0

    3 前面的讨论都没有考虑信号,如果shell在执行过程中收到了信号。
    这个问题我存在有疑惑,因为APUE第十章讲到,system的实现要忽略SIGINT和SIGQUIT,但是我的实验结果并不是这样,如有高手知道,请不吝赐教。

    首先看我的终端信号配置:
    1. libin@libin:~/program/C/Linux/system$ stty -a
    2. speed 38400 baud; rows 36; columns 134; line = 0;
    3. intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z;
    4. rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
    5. -parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
    6. -ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
    7. opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
    8. isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
        Ctrl+C产生SIGINT,Ctrl+\ 产生 SIGQUIT。
        看下测试结果
    1. libin@libin:~/program/C/Linux/system$ ./tsys "sleep 7"
    2. ^Cstatus = 2
    3. abnormal termination,signal number =2
    4. libin@libin:~/program/C/Linux/system$ sleep 7
    5. ^C
    6. libin@libin:~/program/C/Linux/system$ echo $?
    7. 130
        我们可以看到,直接在终端执行sleep 7,然后用Ctrl+C发送SIGINT信号,异常退出,shell返回值为130,130的原因,APUE上解释了,因为SIGINT 等于2,终止状态是128+信号编号,所以为130.

        按照APUE上,我们的system调用应该将SIGINT忽略掉,然后正常返回,同时返回值为130,但是实际上LINUX 下并不是这样的。实际上system的返回值为2,并且异常退出了。

        SIGQUIT信号也是一样的,看我在我的Ubuntu 上做的测试:
    1. libin@libin:~/program/C/Linux/system$ ./tsys "sleep 7"
    2. ^\status = 3
    3. abnormal termination,signal number =3
    4. libin@libin:~/program/C/Linux/system$ sleep 7
    5. ^\退出
    6. libin@libin:~/program/C/Linux/system$ echo $?
    7. 131

        2012年1月1日,我做了下面的实验测试,下面是实验的过程。
    1. root@libin:~/program/C/Linux/system# ./tsys "sleep 50" &
    2. [1] 2518
    3. root@libin:~/program/C/Linux/system# ps -ef


    4. root 2359 2343 0 12:42 pts/0 00:00:00 /bin/bash
    5. root 2518 2359 0 12:55 pts/0 00:00:00 ./tsys sleep 50
    6. root 2519 2518 0 12:55 pts/0 00:00:00 sh -c sleep 50
    7. root 2520 2519 0 12:55 pts/0 00:00:00 sleep 50
    8. root 2521 2359 0 12:56 pts/0 00:00:00 ps -ef
    9. root@libin:~/program/C/Linux/system# kill -3 2520
    10. Quit
    11. status = 33536
    12. normal termination,exit status = 131


    13. root@libin:~/program/C/Linux/system# ./tsys "sleep 50" &
    14. [1] 2568
    15. root@libin:~/program/C/Linux/system# ps -ef

    16. root 2568 2359 0 13:01 pts/0 00:00:00 ./tsys sleep 50
    17. root 2569 2568 0 13:01 pts/0 00:00:00 sh -c sleep 50
    18. root 2570 2569 0 13:01 pts/0 00:00:00 sleep 50
    19. root 2571 2359 0 13:01 pts/0 00:00:00 ps -ef
    20. root@libin:~/program/C/Linux/system# kill -3 2569
    21. status = 3
    22. abnormal termination,signal number =3
     
        从测试结果上看,基本上进程关系如下,system的返回值,其实是shell的终止状态,
    而不是sleep的返回值。所谓屏蔽INTR信号和QUIT信号,指的是tsys这个进程,忽略了INT信号的QUIT信号,但是sh进程,和sleep进程,都没有忽略这两个信号。

        如果给sleep进程 发送SIGQUIT信号,杀死sleep进程,那么sleep会返回131,告诉shell进程我被SIGQUIT杀死了。而sh进程,则是安然退出,所以,依然打印出正常退出的打印,通过调用WEXITSTATUS,看以看出,sleep进程的遗言是131,表明收到QUIT信号。


        下面是测试程序,基本是照抄的APUE。
    1. #define _XOPEN_SOURCE

    2. #include<stdio.h>
    3. #include<stdlib.h>
    4. #include<unistd.h>

    5. #include<signal.h>
    6. #include<sys/wait.h>

    7. void pr_exit(int status)
    8. {
    9.         printf("status = %d\n",status);
    10.     if(WIFEXITED(status))
    11.         {
    12.          printf("normal termination,exit status = %d\n",WEXITSTATUS(status));
    13.         }

    14.         else if(WIFSIGNALED(status))
    15.         {
    16.          printf("abnormal termination,signal number =%d%s\n",
    17.                                 WTERMSIG(status),
    18. #ifdef WCOREDUMP
    19.                                 WCOREDUMP(status)?"core file generated" : "");
    20. #else
    21.                 "");
    22. #endif
    23.         }
    24. }


    25. int main(int argc,char* argv[])
    26. {
    27.         int status;

    28.         if(argc<2)
    29.         {
    30.          fprintf(stderr,"usage:tsys cmd\n");
    31.                  return -1;
    32.         }

    33.         if((status = system(argv[1]) )<0)
    34.         {
    35.          fprintf(stderr,"system error\n");
    36.                 return -2;
    37.         }

    38.         pr_exit(status);
    39.     return 0;
    40. }

    展开全文
  • 在C语言中,如果函数值的类型和return语句中表达式的值不一致,则会如何? 以函数值的类型为准即编译器会自动把return语句中表达式的值的类型转换成函数值的类型

    在C语言中,如果函数值的类型和return语句中表达式的值不一致,则会如何?
    以函数值的类型为准即编译器会自动把return语句中表达式的值的类型转换成函数值的类型

    展开全文
  • 设计一个函数 int isPrime(int n)判断n是否为素数,如果n是素数,函数返回值1,否则返回0。 利用此函数在主函数中,把m到n之间(m,n为偶数,且为输入数据)的所有偶数,写成i=a+b的形式,a,b都是素数。 如果...
  • read函数返回值问题

    千次阅读 2019-09-15 15:32:14
    Read函数读取字符串返回值的问题 1. 前言 在学习socket编程的途中, 通过客户端给服务端发送字符串,然后服务端通过read或者recv来读取数据,然后返回读取的字节数. 我在想read返回的读取字节数有没有包含'\0'或者'\n'...
  • Python 定义生成器的函数返回值

    千次阅读 2019-05-28 21:02:27
    在 Python 的函数中使用 yield 命令,可以将函数转化为一个生成器(generator): def count(): for n in range(99): yield n 此时,函数 count 实际上定义了一个生成器。 使用 type 函数检查,会发现 count 是一个...
  • c++ string函数详细返回值及用法!

    万次阅读 2016-08-04 11:25:14
    下面先罗列出string类的函数有哪一些,然后再罗列出函数的原型,最后到代码的实现 标准C++中提供的string类得功能也是非常强大的,一般都能满足我们开发项目时使用。现将具体用法的一部分罗列如下,只起一个抛砖
  • 2.4函数由于函数用于创建C++程序的模块,在C++的OOP定义至关重要,因此...C++函数分两种:有返回值的和没有返回值的。在标准C++函数库中可以找到这两类函数的例子,您也可以自己创建这两种类型的函数下面首先来看...
  • ***************************************************************************  73 对于C++中类(class) 与结构(struct)的描述正确的为:   A,类中的成员默认是priv
  • 题目:关于构造方法,下面说法正确的是() A、每个类都有至少一个构造方法 B、一个类中可以有多个构造方法 C、构造方法可以有返回值 D、构造方法可以有多个参数 结果:A、B、D 解释: A:即使类中没有定义构造方法...
  • Python 函数参数

    千次阅读 多人点赞 2017-06-01 19:59:41
    对于调用者来说,只需关注如何传递正确的参数,以及函数返回值就足够了,无需了解函数的内部实现(除非想学习、跟踪源码)。 话虽如此,但对于函数的定义来说,灵活性却非常大。除了常规定义的必选参数以外,还...
  • C++ 函数原型

    千次阅读 2017-04-01 09:58:40
    一,函数原型语法 ...函数原型描述了函数到编译器的接口,它将函数返回值的类型以及参数的类型和数量告诉编译器。例如:看函数原型如何影响下面的函数调用。 double cube(double x); int main() { d
  • 下面有关继承、多态、组合的描述,说法错误的是?A、封装,把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏 B、继承可以使用现有类的所有功能,并在无需...
  • 函数和代码复用

    万次阅读 多人点赞 2019-06-06 16:31:41
    1、关于递归函数描述,以下选项中正确的是 A.包含一个循环结构 B.函数比较复杂 C.函数内部包含对本函数的再次调用 D.函数名称作为返回值 答案:D 答案解析:递归函数是指函数内部包含对本函数的再次调用。 ...
  • 名称 malloc,free,calloc,realloc--分配和释放动态内存 概要 #include void *malloc(size_tsize); void free(void *ptr); void *realloc(void*ptr, size_t size); void *calloc(size_...描述
  • 函数式编程的优点

    千次阅读 2014-03-27 09:49:01
     单元测试 ...因为函数式编程的每一个符号都是 final 的,没有函数产生过副作用。...这意味着函数求值的结果只是其返回值,而惟一影响其返回值的就是函数的参数。 这是单元测试者的梦中仙境
  • 【C++】C++类和对象、构造函数和析构函数

    千次阅读 多人点赞 2018-06-03 20:32:37
    它即可包含描述事物的数据,又可包含处理这些数据的函数,类在程序运行时是被用作样板来建立对象的。所以要建立对象,首先必须定义类。 定义类 定义一个类的一般格式为: class 类名{ private: 成员表1; public:...
  • 函数式编程思想概论

    千次阅读 2019-06-26 10:57:16
    函数式编程思想概论前言函数λ 演算λ项绑定变量和自由变量约简α 变换β 约简η 变换纯函数、副作用和引用透明性函数式编程与并发编程总结 原文地址 前言 在讨论函数式编程(Functional Programming)的具体内容...
  • FreeRTOS 队列API函数FreeRTOS 队列API函数获取队列入队信息数目函数描述参数描述获取队列的空闲数目函数描述参数描述删除队列函数描述参数描述 FreeRTOS 队列API函数 FreeRTOS为操作队列提供了非常丰富的API函数...
  • 《Windows核心编程》のWindows返回值

    千次阅读 2010-04-18 22:52:00
    当调用一个Windows函数时,它首先检验传递给它的各个参数的... 下面说说Windows常见的返回值类型:1) VOID:表明该函数运行不可能失败,Windows函数返回值很少是VOID。2) BOOL:如果函数运行失败,返回值是0,
  • Linux函数调用与栈

    千次阅读 2017-06-05 17:31:36
    栈与函数调用惯例(又称调用约定)— 基础篇 记得一年半前参加百度的校招面试时,被问到函数调用惯例的问题。当时只是懂个大概,比如常见函数调用约定类型及对应的参数入栈顺序等。最近看书过程中,重新回顾了这些...
  • 指针函数函数指针

    2017-09-29 09:24:14
    先看下面函数声明,注意,此函数返回值返回值为int *,即返回值是指针类型的。 int *f(int a, int b); 上面的函数声明又可以写成如下形式: int* f(int a, int b); 让指针标志 * 与int紧贴在...
  • Swift learning part 6 - 函数

    千次阅读 2019-07-16 16:30:14
    文章目录函数的定义与调用函数参数与返回值无参数函数多参数函数返回值函数多重返回值函数可选元组返回类型隐式返回的函数函数参数标签和参数名称指定参数标签忽略参数标签默认参数值可变参数输入输出参数函数类型...
  • VISA函数

    千次阅读 2019-12-03 14:14:07
    描述 这个函数用来初始化一个VISA资源管理器,此函数必须要在其他任何VISA函数之前调用。函数通过sesn参数返回一个独立的VISA资源管理器ID。 参数 名称 方向 类型 描述 sesn OUT ViSession 返回一个独一无二的VISA...
  • JavaScript函数,作用域以及闭包

    千次阅读 2017-04-30 01:27:53
    JavaScript函数,作用域以及闭包 1. 函数 (1). 函数定义:函数使用function关键字定义,它可以用在函数定义表达式或者函数声明定义。 a. 函数的两种定义方式: * function functionName() {} * var ...
  • 个人吐血整理,完全弄懂描述符到底是神马

    千次阅读 多人点赞 2019-06-12 15:59:08
    个人吐血整理,完全弄懂描述描述描述符的定义前面的铺垫-各个优先级描述符的...描述符的作用是用来代理另外一个类的属性的 (必须把描述符定义成这个类的类属性,不能定义到构造函数中) 前面的铺垫-各个优先级 ...
  • Swift 基本知识点之四函数

    千次阅读 2016-01-28 14:56:25
    函数(Functions)1.0 翻译:honghaoz 校对:LunaticM2.0 翻译+校对:dreamkidd2.1 翻译:DianQK 定稿:shanks ...函数参数与返回值(Function Parameters and Return Values) 函数参数名称(Function Paramet
  • python 路径函数

    千次阅读 2016-01-21 15:48:41
    本文在http://www.jb51.net/article/21007.htm...功能相当于在path目录下执行dir命令,返回为list类型 print(os.listdir(‘..’)) 2: os.path.walk(path,visit,arg) path :是将要遍历的目录 visit :是一个函数
  • 可能很多朋友对于时间的输出表现有着比较特殊的要求,那么我们只要对时间函数: the_time() 做一些对应的修改,就能达到我们想的效果。用法它的调用格式为:12// 时间输出效果由“字符串”参数决定。&lt;?...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 102,142
精华内容 40,856
关键字:

下面对于函数返回值描述正确的是