perl / awk / sed / bash脚本:具有多个标记的多个缩进级别

时间:2014-06-12 03:10:15

标签: perl bash shell awk sed

我正在尝试基于标记缩进文件的几个级别。 标记参数仅表示下一个单词相同 line是第二级标记。基于这个二级标记, 我想缩小所有内容,直到下一次出现 二级标记。

我尝试这样做的原因是为了调试另一个应用程序。我在顶部和每个函数返回之前打印出数据(以及其间的几个部分)。

提前致谢!

用法是这样的: ./script.sh文件标记

示例数据:

data
thismarker m1
thismarker m2
data
data
thismarker m2
data
data
thismarker m1
data

./script.sh文件的所需输出此标记:

data
data
thismarker m1
 thismarker m2
      data
      data
 thismarker m2
 data
 data
thismarker m1
data

这是我到目前为止所拥有的。我目前正在使用awk,但我会对任何有效的东西感到高兴。它不适用于多个级别,但我不知道如何使用mymarkertwo而不是我目前正在做的事情 - 硬编码hcmarkertwo。

#!/bin/bash                                                                      

file_path=$1                                                                     
markerone=$2                                                                     

 cat ${file_path} | awk -v mone="$markerone" '                                    
    BEGIN {                                                                  
            get_out=0;                                                       
            myfunc="";                                                       
    } {                                                                      

            if ( /${mone}/ ) {                                               
                    mymarkertwo = $2                                         
            }                                                                

            if ( /hcmarkertwo/ ) {                                           
                    get_out=0                                                
                    print $0                                                 
                    getline                                                  

                    do {                                                     
                            if ( /hcmarkertwo/ ) {                           
                                    get_out = 1                              
                                    print $0                                 
                                    getline                                  
                            } else {                                         
                                    $0 = "\t"$0                              
                                    print $0                                 
                                    getline                                  
                            }                                                
                    } while ( get_out == 0 )                                 
            }                                                                
    print $0                                                                 
}
'

4 个答案:

答案 0 :(得分:2)

使用perl one-liner:

perl -lne '
    ($m) = $_ =~ /thismarker (\S+)/;
    pop(@M), $m = "" if $m && @M && $M[-1] eq $m;
    print +("   " x @M), $_;
    push @M, $m if $m;
  ' file.txt

说明:

切换

  • -l:启用行结束处理,指定行终止符
  • -n:为输入文件中的每一行创建一个while(<>){..}循环。
  • -e:告诉perl在命令行上执行代码。

<强>代码

  • $m包含当前行的匹配标记:'m1''m2'
  • @M包含一堆匹配的标记。

答案 1 :(得分:2)

$ cat tst.awk
$1 == marker {
    if ($2 == markerId[depth]) {
        --depth
        nextIndent = --indent
    }
    else {
        markerId[++depth] = $2
        nextIndent = indent + 1
    }
}
{
    printf "%*s%s\n",indent,"",$0
    indent = nextIndent
}

$ cat file
data
thismarker m1
thismarker m2
data
thismarker m1
data
data
thismarker m1
data
thismarker m2
data
data
thismarker m1
data

$ awk -v marker="thismarker" -f tst.awk file
data
thismarker m1
 thismarker m2
  data
  thismarker m1
   data
   data
  thismarker m1
  data
 thismarker m2
 data
 data
thismarker m1
data

请注意,我修改了您的示例输入文件,以显示m1范围内的m2m1范围内sed的情况,因为这通常会在函数中发生调用它使解决方案比不需要考虑更复杂。考虑到输入,我当前发布的perl解决方案将失败,我当前的UNIX框中没有{{1}},我无法开始猜测当前发布的perl咒语是什么,所以我已经不知道这是否有效 - 如果你有perl就试试。

答案 2 :(得分:1)

您需要管理一堆关卡才能正确处理。在伪代码中

line <- file.read
if line.words[0] == "thismarker"
    if line == stack.top
      stack.pop
      print(indent=stack.size) line
    else
      print(indent=stack.size) line
      stack.push(line)
    endif
 else
   print(indent=stack.size) line
endif

答案 3 :(得分:0)

sed '/thismarker m1/,/thismarker m1/{
   /thismarker m1/!s/^/   /
   /thismarker m2/,/thismarker m2/{
      /thismarker m2/!s/^/   /
      }
   }' YourFile

相同的概念,如果几个级别(只是在最后一级结束之前添加新的部分)

/thismarker mX/,/thismarker mX/{
   /thismarker mX/!s/^/   /
   }

说明:

在相同引用的2个标记之间(/thismarker mX/,/thismarker mX/)[标记不在同一行,它是必需的,但请求由它的结构指定],对于没有特定的每一行标记(/thismarker mX/ !),用3个空格(s/^/ /)替换行的开头。 第二级以相同的方式完成,但在&#34;循环内#34;第一级。第三级应该在&#34;循环中做同样的事情。二等等...