在sed中编程rev

时间:2015-06-02 07:48:07

标签: linux sed

我正在尝试编写一个反转输入行的实用程序。以下只是按原样打印行:

#!/bin/sed -f
#insert newline at the beginning
s/^/\n/
#while the newline hasnt moved to the end of pattern space, rotate
: loop
/\n$/{!s/\(.*\)\(.$\)/\2\1/;!b loop}
#delete the newline
s/\n//

关于什么是错的任何想法?

3 个答案:

答案 0 :(得分:5)

/\n$/{!s/\(.*\)\(.$\)/\2\1/;!b loop}
  • !位于地址/范围normaly
  • 之后
  • !b不是goto ,如果我强调你的意思)可能是t(如果发生替换,请转到)
  • $不属于最后一组,只是在
  • 之后

所以这一行是:

/\n$/ !{s/\(.*\)\(.\)$/\2\1/;t loop}

现在,这个代码只是(在最后)没有做任何事情,它在开始时添加一个新行,并通过交换最后一个字符并且不反对任何东西将其移动到最后。

sed 'G
:loop
s/\(.\)\(\n.*\)/\2\1/
t loop
s/.//' YourFile

应该做的伎俩

@TobySpeight仍然增强了代码,无需第一组(代码改编)

答案 1 :(得分:1)

解决方案1 ​​

$ echo -e '123\n456\n789' |sed -nr '/\n/!G;s/(.)(.*\n)/&\2\1/;/^\n/!D;s/\n//p'
321
654
987

核心理念:

  1. 我们需要一个循环来处理每一行,幸运的是我们可以使用D命令来模拟一个循环;
  2. 我们需要遍历一行,这很困难,因为sed每次处理一行;但是我们可以使用sD命令来模拟一行的循环。
  3. 如何避免无限循环?我们需要flag char来识别每行的结尾,\n是完美的选择。
  4. D命令每次\n删除chars util pattern space, 然后强制sed跳转到它的第一个命令,这实际上是一个循环!所以我们还需要在最终字符串之前添加一些无用的placeholder以便D命令删除,我们可以在current line \n之前使用\n中的内容还包括)。
  5. 说明:

    1. /\n/!G:如果当前pattern space包含\n,则表示此命令处于一行处理中;否则,使用G命令将\nhold space附加到pattern spacesed将删除每行的\n,然后再将其放入pattern space),pattern space命令之后G的内容是原始内容和\n
    2. s/(.)(.*\n)/&\2\1/;:使用s命令删除第一个字符(util \n),然后在最终字符串后插入。
    3. /^\n/!D;s/\n//p:如果当前pattern space\n开头,这意味着此行已经解决,请使用s/\n//p删除flag char: \n并打印最后的字符串;否则使用D命令删除useless placeholder,然后跳转到第一个命令来处理第二个字符...
    4. 要进行摘要,循环中pattern space中的内容如下所示:

      123\n [(1)(23\n)] =s=> 123\n23\n1 [(123\n)(23\n)(1)] =D=> 23\n1
      23\n1 [(2)(3\n)1] =s=> 23\n3\n21 [(23\n)(3\n)(2)1] =D=> 3\n21
      3\n21 [(3)(\n)21] =s=> 3\n\n321 [(3\n)(\n)(3)21] =D=> \n321
      \n321 [()(\n)321] =s=> \n321 =!D=> \n321 =s-p=> 321
      

      有一些派生的解决方案:

      解决方案2

      placeholder可以设置另一个以\n结尾的字符串:

      $ echo -e '123\n456\n789' |sed -nr '/\n/!G;s/(.)(.*\n)/USELESS\n\2\1/;/^\n/!D;s/\n//p'
      321
      654
      987
      

      解决方案3

      使用直接循环而不是模糊D命令

      $ echo -e '123\n456\n789' |sed -nr '/\n/!G;s/(.)(.*\n)/&\2\1/;Tend;D;:end;s/\n//p'
      321
      654
      987
      

      解决方案4

      使用.获取第一个字符\n

      $ echo -e '123\n456\n789' |sed -nr '/\n/!G;s/(.)(.*\n)/&\2\1/;/^\n/!D;s/.//p'
      321
      654
      987
      

      解决方案5

      $ echo -e '123\n456\n789' |sed -nr ':loop;/\n/!G;s/(.)(.*\n)/\2\1/;tloop;s/.//p'
      321
      654
      987
      

      此解决方案更容易理解,pattern space res中的内容如下所示:

      123\n [(1)(23\n)] =s=> 23\n1 [(23\n)(1)]
      23\n1 [(2)(3\n)1] =s=> 3\n21 [(3\n)(2)1]
      3\n21 [(3)(\n)21] =s=> \n321 [(\n)(3)21]
      \n321 [()(\n)321] =s=> \n321 =s=> 321
      

答案 2 :(得分:0)

问题是你正在使用错误的工具来尝试理解/使用在1970年代中期发明awk时已经过时的结构。

$ cat file
tsuj
esu
na
etaorporppa
loot

$ awk -v FS= '{rev=""; for (i=1; i<=NF; i++) rev = $i rev; print rev}' file
just
use
an
approproate
tool