Chinaunix

标题: sed中 n命令的疑惑 [打印本页]

作者: lifayi2008    时间: 2014-07-02 15:58
标题: sed中 n命令的疑惑
关于n命令 sed awk 101 hacks中是这样说的:

The sed n command lets you change that flow. The sed n command
will print the current pattern space, clear the current pattern space,
read the next line from the input-file, and continue the command
flow.

Let us assume that you have 2 sed commands before and 2 after the
n command as shown below.
sed-command-1
sed-command-2
n
sed-command-3
sed-command-4

In this case, sed-command-1 and sed-command-2 will be applied to
the current line in the pattern space; when sed encounters the n
command, it will clear the current line from the pattern space, read
the next line from the input-file, and apply sed-command-3 and sedcommand-
4 to this newly read line in the sed pattern space.

在实际试验中
sed -n n employee.txt     假如n有打印功能的话,为什么这里什么也不打印?
sed n employee.txt         假如n没有打印功能的话,这里为什么会打印所有行而不是偶数行?
作者: lifayi2008    时间: 2014-07-02 16:04
n命令是否会打印也受-n选项的控制?
作者: yestreenstars    时间: 2014-07-02 16:07
谁跟你说n有打印功能~
作者: lifayi2008    时间: 2014-07-02 16:22
sed n employee.txt         假如n没有打印功能的话,这里为什么会打印所有行而不是偶数行?回复 3# yestreenstars


   
作者: yestreenstars    时间: 2014-07-02 16:36
回复 4# lifayi2008

执行下面这个试试,就算没有n也照样打印,sed默认就会打印的。
  1. sed '' employee.txt
复制代码

作者: lifayi2008    时间: 2014-07-02 16:59
本帖最后由 lifayi2008 于 2014-07-02 16:59 编辑

你的sed还要恶补 回复 5# yestreenstars


   
作者: expert1    时间: 2014-07-02 17:11
-n 和n搞混了

-n是抑制自动打印
n把下一行放到pattern space,是覆盖。
作者: q1208c    时间: 2014-07-02 17:19
回复 5# yestreenstars


你的sed还要恶补
作者: ly5066113    时间: 2014-07-02 17:23
回复 3# yestreenstars


n 确实有打印功能。
info sed


`n'
     If auto-print is not disabled, print the pattern space, then,
     regardless, replace the pattern space with the next line of input.
     If there is no more input then `sed' exits without processing any
     more commands.
作者: expert1    时间: 2014-07-02 17:28
回复 9# ly5066113


    这样的写法是不是有点奇怪呢,默认是无需加的,只有不打印的时候才会加-n,谁穷极无聊加个‘n'
作者: yestreenstars    时间: 2014-07-02 17:32
@lifayi2008@q1208c
何出此言?
作者: yestreenstars    时间: 2014-07-02 17:34
回复 9# ly5066113

如果自动打印没有被关闭,神马是自动打印?有自动打印还需要你n来打印?
   
作者: lifayi2008    时间: 2014-07-02 17:50
这只是个例子而已,肯定没人会这样用,但是弄清楚每个命令的作用是必须的,要不然以后出现意想不到的结果时,却不清楚问题出在哪回复 10# expert1


   
作者: lifayi2008    时间: 2014-07-02 17:54
read execution print repeat这里面的print就是自动打印,n命令也有自动打印的功能,-n选项抑制这样的自动打印回复 12# yestreenstars


   
作者: 用户名注册后不能更改    时间: 2014-07-02 17:54
回复 13# lifayi2008

为什么弄清一个命令的具体作用不是看man不是看info不是看实际执行结果而是看一个菜鸟自以为是的垃圾言论?

你的逻辑思维需要恶补
作者: yestreenstars    时间: 2014-07-02 18:05
回复 14# lifayi2008

纠结于这种问题只能说明:
1.你研究sed已经走火入魔了;
2.你没事找事做。
   
作者: lifayi2008    时间: 2014-07-02 18:09
我看是你的逻辑思维才需要恶补,每个人有每个人的学习方式,这本书中虽然没有清楚说明:n自动打印,而-n抑制这样的自动打印,但是原文中也没有任何错误之处。绝不是你说的自以为是的菜鸟的言论回复 15# 用户名注册后不能更改


   
作者: q1208c    时间: 2014-07-02 18:46
回复 11# yestreenstars

注意我发的最后一个表情.


我是顺着我楼上的说的.
   
作者: yestreenstars    时间: 2014-07-02 19:48
回复 18# q1208c

人云亦云不可取啊~
   
作者: 用户名注册后不能更改    时间: 2014-07-02 20:41
lifayi2008 发表于 2014-07-02 18:09
我看是你的逻辑思维才需要恶补,每个人有每个人的学习方式,这本书中虽然没有清楚说明:n自动打印,而-n抑制这样的自动打印,但是原文中也没有任何错误之处。绝不是你说的自以为是的菜鸟的言论


已知:
①原文中没有任何错误之处
②你没有看懂来发帖求助
结论:
你的逻辑思维不能理解该文章,所以需要恶补
作者: blackold    时间: 2014-07-02 21:39
n是否有打印功能?

这要看如何理解。

“本质”上讲,n没有打印功能。


就码论码,不要涉及人品)


作者: blackold    时间: 2014-07-02 21:42
回复 1# lifayi2008


    把 n 理解为没有打印功能就可以解释得通了。

这也是认为"没有打印功能"的理由吧。
作者: q1208c    时间: 2014-07-03 08:19
回复 19# yestreenstars



作者: ly5066113    时间: 2014-07-03 08:34
回复 12# yestreenstars


看个例子就好理解了:
  1. $ seq 10 | sed 'n;d'
  2. 1
  3. 3
  4. 5
  5. 7
  6. 9
复制代码
这里自动打印没有关闭,但奇数行之所以会被打印,就是因为 n 的打印功能。
作者: yestreenstars    时间: 2014-07-03 09:09
回复 24# ly5066113

噢,我没看info sed,但我一直都是这样理解的,执行n命令后,先打印当前行,再读取下一行,然后执行后续操作。
   
作者: ly5066113    时间: 2014-07-03 09:15
回复 25# yestreenstars


你的理解是对的,可能就是“n 的打印功能”这个字眼的问题吧。
我是觉得,打印当前行,读取下一行,都是 n 命令的操作,所以称“n 的打印功能”也不为过。
作者: blackold    时间: 2014-07-03 09:38
回复 26# ly5066113

Tim说的也对。关键在于如何理解。

平时我们也经常说"n打印(输出)……"。

但细究起来,倾向于认为n没有打印功能。这样可以更好地一致地解释相关的命令。

按照sed的设计模型,在TOP读入下一行,执行命令,到BOTTOM时自动输出(如果没有关闭自
动打印),再到下一个Cycle。

有些命令会改变控制流,比如n。

n 之所以打印,是n改变了控制流,跳到 BOTTOM引起的自动打印。

其它命令,如s, 为什么没有打印(自动打印)?  因为没到 BOTTOM。

sed 's/xxx/xxx/;' file          # s 之后马上到BOTTOM,自动打印。


作者: blackold    时间: 2014-07-03 09:50
回复 25# yestreenstars


    按照你的说法,你应该认为n有打印功能才对啊。
作者: lifayi2008    时间: 2014-07-03 10:02
亲,n不会跳到bottom,所以这个打印不是因为到execution的bottom才引起的打印,请看一楼中书中的作者举的例子回复 27# blackold


   
作者: lifayi2008    时间: 2014-07-03 10:19
对,n不像p一样会显式的打印,但是n命令会导致sed的自动打印,这样说的话,说n会导致sed控制跳到execution的bottom也对,只不过应用于下一行的命令不会从top开始,而是从n命令后面的命令开始回复 21# blackold


   
作者: yestreenstars    时间: 2014-07-03 10:21
回复 28# blackold

但我不认为是n打印的,我认为是sed自动打印的。
   
作者: ly5066113    时间: 2014-07-03 10:21
回复 27# blackold


我赞同楼主的说法,n 命令不会改变控制流。
在我的例子中:
  1. $ seq 10 | sed 'n;d'
  2. 1
  3. 3
  4. 5
  5. 7
  6. 9
复制代码
因为 d 命令的存在,BOTTOM的自动打印一次都没有执行过,所有的输出都是 n 的打印功能。
作者: yestreenstars    时间: 2014-07-03 10:25
回复 32# ly5066113

说白了,如果关了自动打印,n还能打印吗?
   
作者: blackold    时间: 2014-07-03 10:30
回复 29# lifayi2008


首先,他只是"从功能"上说的。

其次,例子里面也没有说明不会到BOTTOM。

我是从内部的执行流程来说的,当然这是我的理解。没有直接的文档支持。

info 说"如果没有关闭自动打印,n就输出模式空间的内容……"。
是不是等于说n的打印是自动打印?
这应该是可以找到的最“权威"的文档了,但也不直接。

另外,如果没有下一行,n会结束整个脚本,而不会执行n的后续命令。这也是我认为
n跳到BOTTOM的"理由"之一。


作者: blackold    时间: 2014-07-03 10:31
本帖最后由 blackold 于 2014-07-03 10:41 编辑

回复 32# ly5066113


    表面看是这样,但不能证明n不会改变控制流。

我的理解是, sed 在内部存在某种机制,n会跳到BOTTOM,如果有下一行,则读入下一行到
模式空间,再跳到n的下一命令(d);如果没有下行,立即结束整个脚本并退出,不会执行n
的后续命令。
作者: ly5066113    时间: 2014-07-03 10:32
回复 33# yestreenstars


这是两个概念,n的打印功能受到 -n 参数的控制,并不代表n的打印功能使用的是 sed 的自动打印。
作者: blackold    时间: 2014-07-03 10:33
回复 30# lifayi2008

……只不过应用于下一行的命令不会从top开始,而是从n命令后面的命令开始


对于这点,我没有否认。
作者: blackold    时间: 2014-07-03 10:35
回复 36# ly5066113


    如果这样说,那么也可以认为其它命令,比如s命令,也有打印功能,至少在一定条件下。
作者: blackold    时间: 2014-07-03 10:37
本帖最后由 blackold 于 2014-07-03 10:37 编辑

对于这些,都没有找到支持文档。只是大家个人的理解。

怎么理解都行,自己觉得有道理就OK。

另外,如果根据某个理解,无法解释某些命令,应该是某个地方的理解有误了。
作者: lifayi2008    时间: 2014-07-03 10:44
嗯,这个可以用来结贴了,看来101hacks也只能用来入门了
blackold 发表于 2014-07-03 10:30
回复 29# lifayi2008

作者: lifayi2008    时间: 2014-07-03 10:47
为毛引用不过来,直接复制好了


回复 29# lifayi2008


首先,他只是"从功能"上说的。

其次,例子里面也没有说明不会到BOTTOM。

我是从内部的执行流程来说的,当然这是我的理解。没有直接的文档支持。

info 说"如果没有关闭自动打印,n就输出模式空间的内容……"。
是不是等于说n的打印是自动打印?
这应该是可以找到的最“权威"的文档了,但也不直接。

另外,如果没有下一行,n会结束整个脚本,而不会执行n的后续命令。这也是我认为
n跳到BOTTOM的"理由"之一。

thanks
作者: lifayi2008    时间: 2014-07-03 10:54
说n命令不会自动打印,但是会改变控制流跳到bottom,这也能解释“最后一行的问题”,blockold说的应该没错

thanks回复 36# ly5066113


   
作者: ly5066113    时间: 2014-07-03 10:56
回复 35# blackold


但也无法证明 n 会改变控制流。

我们可以看一下其他有控制流改变的命令的描述,如:
       b label
              Branch to label; if label is omitted, branch to end of script.

       d      Delete pattern space.  Start next cycle.

我认为 n 如果真的会改变控制流,那么它应该这样描述:

       n      Branch to end of script, then start next cycle, and skip all commands before n command.


至于“n会结束整个脚本,而不会执行n的后续命令。”这个说可以改变控制流我是赞同的。
作者: blackold    时间: 2014-07-03 11:09
回复 43# ly5066113


但也无法证明 n 会改变控制流。


对,这也不能直接证明n 会改变控制流。

但综合其它现象,我还是倾向于n会改变控制流,n会跳到BOTTOM。

我觉得这符合程序设计的原理(尽管我也不懂这些,如果我来写sed ,我会这样考虑)。

哪一种理解(解释),只要自圆其说就可以接受。

求同存异吧。等发现更直接的证据再说。


作者: blackold    时间: 2014-07-03 11:22

sed什么时候会结束整个脚本?

除了q/Q等显式退出的命令外,其它命令都是在尝试读下一行失败时才退出整个脚本,最后
的出口应该都是TOP/BOTTOM。这样设计起来统一且简单。(个人理解)

q也有类似n的打印功能,如果认为n有打印功能,也应该认为q也有打印功能。


作者: ly5066113    时间: 2014-07-03 11:23
回复 44# blackold


如果说 n 真的会改变控制流,那么 sed 在开始一个新的 cycle 的时候,就需要判断,这个新 cycle 是不是由 n 开始的。
如果是 n 开始的,就要跳过 n 前面的命令,否则就全部执行。
感觉这样设计不是很合理,仅仅为了一个 n 命令就对所有的 cycle 加一次判断。


我更倾向于这样:
所有的功能点都是以函数的形式存在的,在需要的时候加以调用。
假设,打印功能就是函数 print()

自动打印  print()
n 命令     print(); read()
作者: blackold    时间: 2014-07-03 11:28
回复 46# ly5066113


    对,我觉得就在每个cycle的TOP处判断。不只是n,所有命令都这样。

作者: blackold    时间: 2014-07-03 11:35
回复 46# ly5066113


   Tim, 我们知道sed/awk都有既定的设计模型,既然这样,在cycle的端点TOP/BOTTOM做判断也合
乎情理啊。

  
作者: blackold    时间: 2014-07-03 11:36
Tim,  好,不讨论,先保留各自的理解,以后再说。
作者: 用户名注册后不能更改    时间: 2014-07-03 11:40
本来用白话很简单就可以描述清楚的东西,引入了控制流、BOTTOM等术语后,描述起来困难了许多……

默认情况下,当一行数据“处理完了”以后,将其打印出来,若开启-n,则不打印。
n,结束当前行数据的处理,认为其“处理完了”,读入下一行数据,继续处理。

这个“处理完了”用控制流之类的术语应该怎样表述?

如果用BOTTOM表示“处理完了”,那么n大概可以这样表述:
n,跳到BOTTOM,再跳回来并读入下一行数据,然后继续执行当前控制流。

末行n之后结束的原因大概是这样:
锁定技,读入下一行数据失败时,认为当前文件已处理完毕,故结束对其的处理。
作者: ly5066113    时间: 2014-07-03 11:41
回复 49# blackold


嗯,就像你说的,等找到无法解释的命令的时候在说吧。
作者: yinyuemi    时间: 2014-07-03 18:05
本帖最后由 yinyuemi 于 2014-07-03 18:07 编辑

@ly5066113@blackold
恶补了下sed

下载了sed-4.2.2的source code看了看, 附件中把后缀tar改成c

sed.c
case 'n':
          no_default_output = true;  # 当设置-n参数时,no_default_output 为true, 这个很重要,用于execut.c中命令 n 的执行控制,如下面的引用
          break;


execute.c
case 'n':
               if (!no_default_output)  # 如果-n设置,此条件为假,不执行,这也就是为什么sed -n n,没有输出的原因
                output_line(line.active, line.length, line.chomped, &output_file);
              if (test_eof(input) || !read_pattern_space(input, vec, false))
                return -1;
              break;
              
case 'p':  
              output_line(line.active, line.length, line.chomped, &output_file);   # 注意 命令p是不受no_default_output控制的
              break;

if (!no_default_output)    # 此处为全局的判断,即所有命令执行结束之后(t,b等有branch功能的命令除外),判断是否执行print,即auto-print功能
      output_line(line.active, line.length, line.chomped, &output_file);
    return -1;
            


这样看来,n还是有print功能的,并且受到参数-n的控制

execute.tar

46.79 KB, 下载次数: 3

sed.tar

8.63 KB, 下载次数: 2


作者: lifayi2008    时间: 2014-07-03 18:18
本帖最后由 lifayi2008 于 2014-07-03 18:42 编辑

大神     case外面还有个while循环
那是否就如tim所言?n未改变控制流?回复 52# yinyuemi

作者: yestreenstars    时间: 2014-07-03 18:55
回复 52# yinyuemi

那auto-print是调用什么函数?
   
作者: yinyuemi    时间: 2014-07-03 19:32
回复 53# lifayi2008


    从源码看,个人觉得n改变控制流只发生在末行,或 没有任何可以读入 时会改变(return -1),
   
作者: yinyuemi    时间: 2014-07-03 19:33
回复 54# yestreenstars


我觉得是这里。。。

    if (!no_default_output)    # 此处为全局的判断,即所有命令执行结束之后(t,b等有branch功能的命令除外),判断是否执行print,即auto-print功能
      output_line(line.active, line.length, line.chomped, &output_file);
     return -1;
作者: 用户名注册后不能更改    时间: 2014-07-03 19:35
回复 54# yestreenstars

case 'n':
               if (!no_default_output)  # 如果-n设置,此条件为假,不执行,这也就是为什么sed -n n,没有输出的原因
                output_line(line.active, line.length, line.chomped, &output_file);
              if (test_eof(input) || !read_pattern_space(input, vec, false))
                return -1;
              break;
              
case 'p':  
              output_line(line.active, line.length, line.chomped, &output_file);   # 注意 命令p是不受no_default_output控制的
              break;

if (!no_default_output)    # 此处为全局的判断,即所有命令执行结束之后(t,b等有branch功能的命令除外),判断是否执行print,即auto-print功能
      output_line(line.active, line.length, line.chomped, &output_file);
    return -1;


auto-print只是层主为默认的打印功能起的名字,执行的是黄色部分代码,条件的判断与打印函数的调用均与n中的对应部分完全类似。
作者: yestreenstars    时间: 2014-07-03 20:11
研究这个有助于提高写sed的能力吗?结帖吧!
作者: 用户名注册后不能更改    时间: 2014-07-03 20:17
回复 58# yestreenstars

怎么还敢说这种话,小心楼主又跳出来

lifayi2008 发表于 2014-07-02 16:59
你的sed还要恶补  回复 5# yestreenstars

作者: Herowinter    时间: 2014-07-03 20:20
回复 52# yinyuemi
大神,膜拜啊。

   
作者: ly5066113    时间: 2014-07-03 20:55
回复 52# yinyuemi


像SS致敬!

看来我猜对了,都是调用同一个打印函数,output_line()
作者: yinyuemi    时间: 2014-07-03 22:32
回复 61# ly5066113


    Tim兄言重了,我只是代码的搬运工而已~
   
作者: lifayi2008    时间: 2014-07-04 09:26
懒得回复你,你丫就是来吵架的回复 59# 用户名注册后不能更改


   
作者: cjaizss    时间: 2014-07-04 09:36
......一个这么傻的问题聊了这么多页......
作者: blackold    时间: 2014-07-04 09:44
回复 52# yinyuemi


    NX,佩服!

    我还没弄清楚。
作者: blackold    时间: 2014-07-04 09:46
回复 64# cjaizss


    脑袋笨啊,你就鄙视一下吧。
作者: blackold    时间: 2014-07-04 09:48
回复 58# yestreenstars


    我觉得有啊,没有不讨论这种傻问题了。

    还是有用的,至少可以活跃论坛气氛吧。

    不讨论就不知道真相。
作者: yestreenstars    时间: 2014-07-04 09:51
回复 67# blackold

黑哥,不要在意这些细节~
   
作者: reyleon    时间: 2014-07-04 09:53
不明真相的人围观路过.
作者: expert1    时间: 2014-07-04 10:03

捞2分
作者: blackold    时间: 2014-07-04 10:41
本帖最后由 blackold 于 2014-07-04 10:53 编辑

@lifayi2008
@ly5066113@yestreenstars@yinyuemi

从源码看,确实如 Tim 所言,n 有打印功能。

我的理解是错误的。

主要代码(http://ftp.gnu.org/gnu/sed/sed-4.2.tar.bz2)如下:

sed.c

  1. /* If set, don't write out the line unless explicitly told to */
  2. bool no_default_output = false;

  3. ...

  4. main (...)
  5. {
  6.     ...
  7.     # 命令行参数处理
  8.             switch (opt)
  9.                 {
  10.                 case 'n':
  11.                     no_default_output = true;
  12.                     break;
  13.     ...

  14.     check_final_program(the_program);

  15.     return_code = process_files(the_program, argv+optind);

  16. }
复制代码
execute.c

  1. process_files (...)
  2. {
  3. ...
  4.         status = EXIT_SUCCESS;
  5.         while (read_pattern_space(&input, the_program, false))
  6.             {
  7.                 status = execute_program(the_program, &input);
  8.                 if (status == -1)
  9.                     status = EXIT_SUCCESS;
  10.                 else
  11.                     break;
  12.             }
  13.         closedown(&input);
  14.         ...
  15. }

  16. execute_program(...)
  17. {
  18. ...
  19.         switch(...)
  20.         # 命令处理

  21.                             case 'n':
  22.                                 if (!no_default_output)
  23.                                     output_line(line.active, line.length, line.chomped, &output_file);
  24.                                 if (test_eof(input) || !read_pattern_space(input, vec, false))
  25.                                     return -1;
  26.                                 break;
  27. ...
  28.                             case 'q':
  29.                                 if (!no_default_output)
  30.                                     output_line(line.active, line.length, line.chomped, &output_file);
  31. ...
  32.                             case 'N':
  33.                                 str_append(&line, "\n", 1);

  34.                                 if (test_eof(input) || !read_pattern_space(input, vec, true))
  35.                                     {
  36.                                         line.length--;
  37.                                         if (posixicity == POSIXLY_EXTENDED && !no_default_output)
  38.                                             output_line(line.active, line.length, line.chomped,
  39.                                                         &output_file);
  40.                                         return -1;
  41.                                     }
  42.                                 break;
  43. ...



  44.         if (!no_default_output)
  45.             output_line(line.active, line.length, line.chomped, &output_file);
  46.         return -1;
  47. }
复制代码

作者: yestreenstars    时间: 2014-07-04 10:48
回复 71# blackold

向黑哥学习!
   
作者: blackold    时间: 2014-07-04 10:50
之前把 auto-print 理解为sed处理流程中的固定一块代码,所有的auto-print都在这里处
理。

从源码看,auto-print 只是由全局变量 no_default_output 所控制的输出。

这样说来,q, N 也有打印功能。

而其它命令,如i和c命令, 的输出,不称为 auto-print, 因为不受 no_default_output
控制。

作者: blackold    时间: 2014-07-04 10:56
回复 54# yestreenstars

关键就是这里理解错了。

所谓的 auto-print 并没有专门的代码块(函数)来实现,由 no_default_output 所控制的
输出都称为 auto-print。

在源码中,它可能在这里,也可能在那里。
作者: blackold    时间: 2014-07-04 10:58
回复 53# lifayi2008


  从源码看,n 没有直接改变控制流,它通过返值来让其它函数改变控制流。
作者: yestreenstars    时间: 2014-07-04 11:05
回复 74# blackold

原理这东西,实在不想研究太深,作为一个使用者,我知道怎么用就行了~
   
作者: 用户名注册后不能更改    时间: 2014-07-04 13:08
回复 63# lifayi2008

6楼说了那么嘲讽的话,还好意思说我是来吵架的,看来和你相比,我的脸皮还需要恶补啊




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2