注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

bash中异步任务及'&'操作符  

2012-11-17 15:02:12|  分类: bash分析 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、异步任务
bash中的语法的确诡异,可能是脚本语言本身相对于C语言这些编译型语言来说添加一个功能相对简单一些的缘故吧。在有些时候,我们需要在脚本里创建一些异步任务来运行,这个有时候是必选而不是可选项,这种应用场景就是之前说的svn的post-commit hook中重启apache服务器。这个是题外话,只是为了说明在某些情况下异步任务执行的必要性。
然后就是说异步任务的创建,大家其实都知道是通过在一个命令的最后添加一个'&'来完成,这个可能是比较简单的,但是在实际的应用中,一个命令可能会涉及比较多的其它功能,例如和重定向操作符的合作、和各种其它的逻辑与操作符联合在一起使用就比较有麻烦一些。因为在bash中,‘&’d的另一个作用就是和分号‘;’'一样用来分隔命令,并且把‘&’之前的命令放在后台运行。
事情是这样的:当时为了创建一个简单的异步任务,就是执行了一个
some command &
来把some command命令放在后台运行,然后运行一下发现没有达到预期的目的,还需要把这个命令的标准输出给重定向一下,所以就随手加了一个重定向的操作,之后的命令转换为
some command & >some.log
然后再次运行这个任务的时候,发现结果就不再是预料内结果了。
二、抽象成一个简单例子的现象
[root@Harry bashasync]# cat async.sh
#!/bin/sh
echo hello wordl & >greeting.txt

[root@Harry bashasync]# ll
total 4
-rwxr-xr-x. 1 root root 44 2012-11-17 14:11 async.sh
[root@Harry bashasync]# ll
total 4
-rwxr-xr-x. 1 root root 44 2012-11-17 14:11 async.sh
[root@Harry bashasync]# ./async.sh
hello wordl
[root@Harry bashasync]# ll
total 4
-rwxr-xr-x. 1 root root 44 2012-11-17 14:11 async.sh
-rw-r--r--. 1 root root  0 2012-11-17 14:44 greeting.txt
[root@Harry bashasync]# cat greeting.txt  新生成的重定向输出文件内容为空
[root@Harry bashasync]#
三、分析一下bash的语法分析和逻辑
同样是在parse.y文件中,对于这个语法的解析位于
simple_list1:    simple_list1 AND_AND newline_list simple_list1
            { $$ = command_connect ($1, $4, AND_AND); }
    |    simple_list1 OR_OR newline_list simple_list1
            { $$ = command_connect ($1, $4, OR_OR); }
    |    simple_list1 '&' simple_list1
            {
              if ($1->type == cm_connection)
                $$ = connect_async_list ($1, $3, '&');
              else
                $$ = command_connect ($1, $3, '&');
            }
    |    simple_list1 ';' simple_list1
            { $$ = command_connect ($1, $3, ';'); }

    |    pipeline_command
            { $$ = $1; }
    ;
再具体一点说,对于
echo hello wordl & >greeting.txt
这个语句来说
echo hello wordl 和>greeting.txt均规约为simple_list1语法单位,而中间的'&'和语法文件中的‘&’直接对应。
在对于‘&’连接的命令来说,bash解析器执行的逻辑为:
execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
  /* Do the first command asynchronously. */
    case '&':
      tc = command->value.Connection->first;
      if (tc == 0)
    return (EXECUTION_SUCCESS);

      rp = tc->redirects;

      if (ignore_return)
    tc->flags |= CMD_IGNORE_RETURN;
      tc->flags |= CMD_AMPERSAND;

      /* If this shell was compiled without job control support,
     if we are currently in a subshell via `( xxx )', or if job
     control is not active then the standard input for an
     asynchronous command is forced to /dev/null. */
#if defined (JOB_CONTROL)
      if ((subshell_environment || !job_control) && !stdin_redir)
#else
      if (!stdin_redir)
#endif /* JOB_CONTROL */
    tc->flags |= CMD_STDIN_REDIR;

      exec_result = execute_command_internal (tc, 1, pipe_in, pipe_out, fds_to_close);
      QUIT;

      if (tc->flags & CMD_STDIN_REDIR)
    tc->flags &= ~CMD_STDIN_REDIR;

      second = command->value.Connection->second;
      if (second)
    {
      if (ignore_return)
        second->flags |= CMD_IGNORE_RETURN;

      exec_result = execute_command_internal (second, asynchronous, pipe_in, pipe_out, fds_to_close);
    }

      break;
可以看到,bash是把‘&’之前的内容作为异步执行的命令体,而之后的内容作为另一个命令,这也就是说,重定向的优先级要高于后台运行的优先级。
对于没有命令体的重定向操作,它唯一的作用就是创建(存在则清空)一个对应的文件。
四、顺便看一下其它的连接符操作
/* Just call execute command on both sides. */
    case ';':
      if (ignore_return)
    {
      if (command->value.Connection->first)
        command->value.Connection->first->flags |= CMD_IGNORE_RETURN;
      if (command->value.Connection->second)
        command->value.Connection->second->flags |= CMD_IGNORE_RETURN;
    }
      executing_list++;
      QUIT;
      execute_command (command->value.Connection->first);
      QUIT;
      exec_result = execute_command_internal (command->value.Connection->second,
                      asynchronous, pipe_in, pipe_out,
                      fds_to_close);
      executing_list--;
      break;
……
  case AND_AND: 逻辑与
    case OR_OR: 逻辑或
      if (asynchronous)
    {
      /* If we have something like `a && b &' or `a || b &', run the
         && or || stuff in a subshell.  Force a subshell and just call
         execute_command_internal again.  Leave asynchronous on
         so that we get a report from the parent shell about the
         background job. */
      command->flags |= CMD_FORCE_SUBSHELL;
      exec_result = execute_command_internal (command, 1, pipe_in, pipe_out, fds_to_close);
      break;
    }

      /* Execute the first command.  If the result of that is successful
     and the connector is AND_AND, or the result is not successful
     and the connector is OR_OR, then execute the second command,
     otherwise return. */

      executing_list++;
      if (command->value.Connection->first)
    command->value.Connection->first->flags |= CMD_IGNORE_RETURN;

      exec_result = execute_command (command->value.Connection->first);
      QUIT;
      if (((command->value.Connection->connector == AND_AND) &&
       (exec_result == EXECUTION_SUCCESS)) ||
      ((command->value.Connection->connector == OR_OR) && 逻辑或只有在前一个失败的时候才执行第二个命令
       (exec_result != EXECUTION_SUCCESS)))
    {
      if (ignore_return && command->value.Connection->second)
        command->value.Connection->second->flags |= CMD_IGNORE_RETURN;

      exec_result = execute_command (command->value.Connection->second);
    }
      executing_list--;
      break;
这里的分析纯粹出于好奇,实际意义不大……。
  评论这张
 
阅读(1203)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017