String sed帮助:基于下一行有条件地替换(美化ascii树输出)

String sed帮助:基于下一行有条件地替换(美化ascii树输出),string,awk,sed,String,Awk,Sed,我有一个程序,输出如下: 1405565344 | +- 1405722995 | | | +- 1405722998 | | | | | +- 1405724849 | | | +- 1406051621 | +- 1406051709 +- 1406733328 [END OF OUTPUT -- OUTPUT DOES NOT INCLUDE THIS LINE] 请注意,最后一行不是输出

我有一个程序,输出如下:

1405565344
  |
  +- 1405722995
  |   |
  |   +- 1405722998
  |   |   |
  |   |   +- 1405724849
  |   |     
  |   +- 1406051621
  |     
  +- 1406051709
  +- 1406733328


[END OF OUTPUT -- OUTPUT DOES NOT INCLUDE THIS LINE]
请注意,最后一行不是输出的一部分;如果我不在最后两行(大部分为空白)后面添加内容,那么最后两行将被隐藏。还要注意,在最后一个条目之后的空白行上有多个空格,但不显示它们。

所以我想把它做得更紧凑更好。。漂亮的使用以下
sed
命令

sed -e 's,|,│,g'     \
    -e "s,+,└,"      \
    -e "s,- ,─,"     \
    -e '/^[ │]*$/d'  
我可以将上述输入转换为:

1405565344
  └─1405722995
  │   └─1405722998
  │   │   └─1405724849
  │   └─1406051621
  └─1406051709
  └─1406733328
好多了。理想情况下,我希望是这样:

1405565344
  ├─1405722995
  │   ├─1405722998
  │   │   └─1405724849
  │   └─1406051621
  ├─1406051709
  └─1406733328
我知道差别很小,但它更有意义,并且更符合我程序的其他输出

所以基本上:我想要一种方法使
sed
有条件地用
+
替换
+
,取决于它后面的行。如果不采取完全不同的路线,似乎几乎是不可能的

有什么想法吗

sed -n -e '/| *$/ d;1h;1!H
$ {x
:a
   s/\(\n[ |]*\)+\([^[:cntrl:]]*\1[|+]\)/\1├\2/;t a
:b
   s/\(\n[ |]*\)+/\1└/;t b
   s/|/│/g;s/- /─/g;p
   }' YourFile
我应该做你的工作。使用图形字符以外的其他字符进行测试(不要在我的aix上传递)。 如果从一行的行首到下一行的行首(第一个新行之后的行首)的模式相同,则测试切换到
T
。我使用[:cntrl:]捕捉非换行符,因此,如果有特殊字符被视为控制字符,它将失败(不要认为文件中有)。 如果不是,则角点处的情况(带+)更改de plus[为优化sed模式分组而修改][为角点字符而修改,以及具有相同模式的连续两行以+]结尾的情况]

我应该做你的工作。使用图形字符以外的其他字符进行测试(不要在我的aix上传递)。 如果从一行的行首到下一行的行首(第一个新行之后的行首)的模式相同,则测试切换到
T
。我使用[:cntrl:]捕捉非换行符,因此,如果有特殊字符被视为控制字符,它将失败(不要认为文件中有)。
如果不是,则在角点处的情况(带有+)更改de plus的行[为优化sed模式分组而修改][为角点字符而修改,以及在相同模式下以+]结尾的两个连续行的情况下]

我的逻辑是使用awk,|作为标记器,并使用$NF的长度来决定打印哪一行

cat <ip_file.txt> | awk -F'|' '{if(length($NF)>5)print $0;}'

注意:替换+-仍在等待中

我的逻辑是使用awk、|作为标记器,并使用$NF的长度来决定打印哪一行

cat <ip_file.txt> | awk -F'|' '{if(length($NF)>5)print $0;}'
注意:更换+-仍在等待中

Awk方式
可能会有很大的改进,但效果与预期一致。
我的机器无法显示
所以只要用它们替换
#
L

如果有人有任何改进,请告诉我,我会更新

awk '/\+/{a=$0;b=index($0,"+");next}
a{if(substr($0,b,1)=="|"){$0=gensub(/+/,"#","g",a)}else{$0=gensub(/+/,"L","g",a)}}
/[1-9]/{print $0}' file
输出 Awk方式
可能会有很大的改进,但效果与预期一致。
我的机器无法显示
所以只要用它们替换
#
L

如果有人有任何改进,请告诉我,我会更新

awk '/\+/{a=$0;b=index($0,"+");next}
a{if(substr($0,b,1)=="|"){$0=gensub(/+/,"#","g",a)}else{$0=gensub(/+/,"L","g",a)}}
/[1-9]/{print $0}' file
输出
这就行了。gawk的match()函数设置变量RSTART。我检查下一行以查看该位置的字符

gawk '
    function g(line) {
        gsub(/#/,   "├", line)
        gsub(/-/,   "─", line)
        gsub(/[+]/, "└", line)
        gsub(/[|]/, "│", line)
        return line
    }
    /^[[:blank:]|]*$/ {next} 
    prev {
        while (match(prev, /[+]/)) {
            c=substr($0, RSTART, 1); 
            if (c == "+" || c == "|")
                sub(/[+]/, "#", prev)
            else 
                break
        }
        print g(prev)
    }
    {prev=$0} 
    END {print g($0)}
' file
在行动中:

$ echo "1405565344
  |
  +- 1405722995
  |   |
  |   +- 1405722998
  |   |   |
  |   |   +- 1405724849
  |   |     
  |   +- 1406051621
  |   +- foobar
  |     
  +- 1406051709
  +- barfoo" |
awk '
    function g(line) {
        gsub(/[+]/, "└", line)
        gsub(/#/, "├", line)
        gsub(/-/,"─", line)
        gsub(/[|]/, "│", line)
        return line
    }
    /^[[:blank:]|]*$/ {next} 
    prev {
        while (match(prev, /[+]/)) {
            c=substr($0, RSTART, 1); 
            if (c == "+" || c == "|")
                sub(/[+]/, "#", prev)
            else 
                break
        }
        print g(prev)
    }
    {prev=$0} 
    END {print g($0)}
'

这就行了。gawk的match()函数设置变量RSTART。我检查下一行以查看该位置的字符

gawk '
    function g(line) {
        gsub(/#/,   "├", line)
        gsub(/-/,   "─", line)
        gsub(/[+]/, "└", line)
        gsub(/[|]/, "│", line)
        return line
    }
    /^[[:blank:]|]*$/ {next} 
    prev {
        while (match(prev, /[+]/)) {
            c=substr($0, RSTART, 1); 
            if (c == "+" || c == "|")
                sub(/[+]/, "#", prev)
            else 
                break
        }
        print g(prev)
    }
    {prev=$0} 
    END {print g($0)}
' file
在行动中:

$ echo "1405565344
  |
  +- 1405722995
  |   |
  |   +- 1405722998
  |   |   |
  |   |   +- 1405724849
  |   |     
  |   +- 1406051621
  |   +- foobar
  |     
  +- 1406051709
  +- barfoo" |
awk '
    function g(line) {
        gsub(/[+]/, "└", line)
        gsub(/#/, "├", line)
        gsub(/-/,"─", line)
        gsub(/[|]/, "│", line)
        return line
    }
    /^[[:blank:]|]*$/ {next} 
    prev {
        while (match(prev, /[+]/)) {
            c=substr($0, RSTART, 1); 
            if (c == "+" || c == "|")
                sub(/[+]/, "#", prev)
            else 
                break
        }
        print g(prev)
    }
    {prev=$0} 
    END {print g($0)}
'

IMHO,你已经超出了sed应该做什么的范围。Sed它真的很强大,并且具有hold string的概念,这可能会有所帮助。但它会给人一种难以管理的丑陋混乱:如果它太复杂,就使用python(resp perl,ruby,…)@SergeBallesta:这也是我的感觉;不过,我想我还是会问的。谢谢你的反馈。IMHO,你已经超出了sed应该做什么的范围。Sed它真的很强大,并且具有hold string的概念,这可能会有所帮助。但它会给人一种难以管理的丑陋混乱:如果它太复杂,就使用python(resp perl,ruby,…)@SergeBallesta:这也是我的感觉;不过,我想我还是会问的。谢谢你的反馈。非常好!我最初的想法是用
awk
来做,但时间太晚了,我甚至没有尝试。我在学习你的代码。你做了最难的部分;现在我只需要将
-
替换为
和带有
。非常好!我最初的想法是用
awk
来做,但时间太晚了,我甚至没有尝试。我在学习你的代码。你做了最难的部分;现在我只需要将
-
替换为
和带有
sed
太可笑了。。。但是哇,这太棒了@NeronLeVelu。就输出而言,只需一个简单的调整即可实现完美——将
/\1L/
更改为
/\1└/。我说得太快了。你那惊人的代码并没有处理一些简单的情况,比如我刚刚添加到主帖子中的情况。你说得对,我忘记了这个情况,只是一个示例调优:-)(更改
\1 |
后面的行:a by
\1[|+]
(在回复中修改)
sed
太可笑了……但是哇,这真是太棒了@NeronLeVelu。就输出而言,只需一个简单的调整,它就是完美的——将
/\1L/
更改为
/\1└/。我说得太快了。你那惊人的代码不能处理一些简单的情况,比如我刚刚在主帖子中添加的情况。你是对的,我忘记了这个情况,只是一个示例调优:-)(更改
\1 |
后面的行:a by
\1[|+]
(在回复中修改)这是很酷的Raghuram——我使用
awk
,我从来没有想过要这样做;但是,它并没有真正帮助解决我遇到的问题(因为我可以用一个简单的sed命令做那么多).这是很酷的Raghuram--我使用
awk
,我从来没有想过这样做;但是,它并没有真正帮助解决我的问题(因为我可以用一个简单的sed命令做那么多)。太棒了,glenn!我喜欢