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

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

sscanf、bash重定向及sql别名  

2012-11-21 00:22:48|  分类: 点滴细节 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、sscanf
在一些简单的配置文件中,可能是通过一个非常简单的二维表结构来读取一个配置信息,这个配置表再简单来说其实就是一个数据库中select出来的一个结构,或者更加直观的来说就是说一个excel文件呈现给我们的一个形式。这种格式的特点或者说优点就是在可配置和可读性方面达到了一个比较好的折中。现在一个简单的问题是这个文件的读取操作,通常我们希望在文件中能够有一个清晰的格式,例如为了对齐,可以在不同的列之间出入任意多个的空白键(blank字符,包括了space和tab),这个空白分隔符的数量在扫描的时候可能需要使用sscanf来读取,而读取的时候需要在format中配置的空白符的数量和真正的配置文件中一致吗?
如果始终维护一致性,那么如果某一列加入了一个非常长的元素,为了可读性,整个一列和前一列的距离都会增加,此时代码中的格式是否要和配置文件中的分隔格式战战兢兢地一致呢?
如果配置文件中全部是数字,那么答案是否定的。我们看一下ssanf的说明:
A directive is one of the following:
?
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.

? An ordinary character (i.e., one other than white space or '%'). This character must exactly match the next character of input.

? A conversion specification, which commences with a '%' (percent) character. A sequence of characters from the input is converted according to this specification, and the result is placed in the corresponding pointer argument. If the next item of input does not match the conversion specification, the conversion fails-this is a matching failure.
格式化指令中的空格对于format来说是透明的,format不会处理这个空白,存在的意义主要是为了让format的格式看起来比较便于维护。文档对于程序员来说不是最好的,代码才是。所以看一下glibc中的处理glibc-2.7\stdio-common\vfscanf.c
   fc = *f++;
      if (fc != '%')
    {
      /* Remember to skip spaces.  */
      if (ISSPACE (fc))
        {
          skip_space = 1;
          continue;对于格式化字符串中的空白,不断的跳过该字符,并且设置skip_space标志,表示已经跳过了空白
        }

      /* Read a character.  */
      c = inchar ();

      /* Characters other than format specs must just match.  */
      if (__builtin_expect (c == EOF, 0))
        input_error ();

      /* We saw white space char as the last character in the format
         string.  Now it's time to skip all leading white space.  */
      if (skip_space)如果格式化中有空白,那么可以匹配输入中的任意多个空白,否则输入中的空白一直保留
        {
          while (ISSPACE (c))
        if (__builtin_expect (inchar () == EOF, 0))
          input_error ();
          skip_space = 0;
        }

      if (__builtin_expect (c != fc, 0))
        {
          ungetc (c, s);
          conv_error ();
        }

      continue;
    }
……
    if (skip_space || (fc != L_('[') && fc != L_('c') 如果格式化字符串中有空白,或者说格式化中没有包含这里四个字符中的任意一个,那么开始跳过输入字符串中的引导空白。注意,这里只是一个常识,所以也就对应于man手册中所说的人一个多个(包括0个)
             && fc != L_('C') && fc != L_('n')))
    {
      /* Eat whitespace.  */
      int save_errno = errno;
      __set_errno (0);
      do
        /* We add the additional test for EOF here since otherwise
           inchar will restore the old errno value which might be
           EINTR but does not indicate an interrupt since nothing
           was read at this time.  */
        if (__builtin_expect ((c == EOF || inchar () == EOF)
                  && errno == EINTR, 0))
          input_error ();
      while (ISSPACE (c));
      __set_errno (save_errno);
      ungetc (c, s);
      skip_space = 0;
    }
二、bash中的复杂语句重定向
有些时候,我们希望多次执行一个函数,每次给出的参数不一样。这个情况下是因为有些命令本身并不支持读取一个在第一节中所说的配置文件逐行按列配置的格式,有时候是重启进程是为了清楚程序中的某些特殊缓存,此时我们希望将一个shell的特殊控制语句进行转换。看一下bash中对于复杂命令重定向的处理:bash-4.1\parse.y
command:    simple_command
            { $$ = clean_simple_command ($1); }
    |    shell_command
            { $$ = $1; }
    |    shell_command redirection_list
shell_command:    for_command
            { $$ = $1; }
    |    case_command
            { $$ = $1; }
     |    WHILE compound_list DO compound_list DONE
            { $$ = make_while_command ($2, $4); }
    |    UNTIL compound_list DO compound_list DONE
            { $$ = make_until_command ($2, $4); }
    |    select_command
            { $$ = $1; }
    |    if_command
            { $$ = $1; }
    |    subshell
            { $$ = $1; }
    |    group_command
            { $$ = $1; }
    |    arith_command
            { $$ = $1; }
    |    cond_command
            { $$ = $1; }
    |    arith_for_command
            { $$ = $1; }
    ;

simple_command:    simple_command_element
            { $$ = make_simple_command ($1, (COMMAND *)NULL); }
    |    simple_command simple_command_element
            { $$ = make_simple_command ($2, $1); }
    ;
从命令行上看,命令分为两部分,一个是simple_command,简单命令就是我们最为常见的
echo hello world
这种形式的命令,它们由纯粹的平凡单词组成(即不包含bash内置的for、select之类的命令),或者更加不严谨的说,就是命令的开始不是一个bash关键字的命令,可以认为是shell命令中的屌丝。
相反地,那些shell_command则表示了shell的嫡系内置命令,例如for循环、while循环,不论怎样,从语法文件中可以看到,bash是支持将这样的整个一个shell内置命令(不论这个命令有多复杂)是可以被单个重定向的,对应的就是上面的一个redirection_list。
这样我们就可以结合bash的read命令来读取一个命令,进而让一个命令来多次执行。
while read col1 col2 …… coln
do
command col1
done < someconfig.ini
三、mysql中的表、列重命名
在sql中可以通过as来修改一个列或者表的名字,大部分的文档都是说这样可以避免输入一个冗长的名字,所以alias一个比较短的名字。但是在另外一些场景中,一个数据库的字段是可能会被转义的。或者一些表格定义的时候,它就是准备涉及为一种通用的存储,所以字段的命名可能就是D1、D2等,不同的引用会根据自己的需要将这些字段解释为具体业务赋予的含义,例如
D1 as age D2 as height
来使sql语句更加的可读性。
再极端的说,我们使用高级语言来管理内存和控制语句,也不就是为了使用我们可读的字符形式来表达我们的意思,从而达到更高的可维护性吗?
  评论这张
 
阅读(633)| 评论(0)
推荐 转载

历史上的今天

评论

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

页脚

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