Bash 动态文档索引

Bash 动态文档索引,bash,awk,substitution,string-substitution,Bash,Awk,Substitution,String Substitution,我有一个文档,需要在其中动态创建/更新索引。我正试图用awk来完成这个。我有一个部分工作的例子,但现在我被难倒了 示例文档如下所示 numbers.txt: #) Title #) Title #) Title #.#) Subtitle #.#.#) Section #.#) Subtitle #) Title #) Title #.#) Subtitle #.#.#) Section #.#) Subti

我有一个文档,需要在其中动态创建/更新索引。我正试图用awk来完成这个。我有一个部分工作的例子,但现在我被难倒了

示例文档如下所示

numbers.txt:
    #) Title
    #) Title
    #) Title
    #.#) Subtitle
    #.#.#) Section
    #.#) Subtitle
    #) Title
    #) Title
    #.#) Subtitle
    #.#.#) Section
    #.#) Subtitle
    #.#.#) Section
    #.#.#.#) Subsection
    #) Title
    #) Title
    #.#) Subtitle
    #.#.#) Section
    #.#.#.#) Subsection
    #.#.#.#) Subsection
numbers.sh:
    awk '{for(w=1;w<=NF;w++)if($w~/^#\)/){sub(/^#/,++i)}}1' number.txt
所需的输出将是:

1) Title
2) Title
3) Title
3.1) Subtitle
3.1.1) Section
3.2) Subtitle
4) Title
5) Title
5.1) Subtitle
5.1.1) Section
5.2) Subtitle
5.2.1) Section
5.2.1.1) Subsection
6) Title
7) Title
7.1) Subtitle
7.1.1) Section
7.1.1.1) Subsection
7.1.1.2) Subsection
我拥有的部分工作的awk代码如下

numbers.txt:
    #) Title
    #) Title
    #) Title
    #.#) Subtitle
    #.#.#) Section
    #.#) Subtitle
    #) Title
    #) Title
    #.#) Subtitle
    #.#.#) Section
    #.#) Subtitle
    #.#.#) Section
    #.#.#.#) Subsection
    #) Title
    #) Title
    #.#) Subtitle
    #.#.#) Section
    #.#.#.#) Subsection
    #.#.#.#) Subsection
numbers.sh:
    awk '{for(w=1;w<=NF;w++)if($w~/^#\)/){sub(/^#/,++i)}}1' number.txt
numbers.sh:

awk'{for(w=1;w我已经为您实现了一个awk脚本!它仍然适用于四个以上的级别索引!)

我将尝试用内联注释对此进行解释:

最后,您可以执行它:

./script.awk <path_to_number.txt>
因此,如果您有这个number.txt

#) Title
#) Title
#) Title
#.#) Subtitle
#.#.#) Section
#.#) Subtitle
#) Title
#) Title
#.#) Subtitle
#.#.#) Section
#.#) Subtitle
#.#.#) Section
#.#.#.#) Subsection
#) Title
#) Title
#.#) Subtitle
#.#.#) Section
#.#.#.#) Subsection
#.#.#.#.#) Subsection
#.#.#.#.#) Subsection
#.#.#.#.#) Subsection
#.#.#.#.#.#) Subsection
#.#.#.#.#) Subsection
#.#.#.#.#.#) Subsection
#.#.#.#.#.#) Subsection
#.#.#.#.#.#) Subsection
#.#.#.#.#.#) Subsection
#.#.#.#.#) Subsection
#.#.#.#) Subsection
#.#.#) Section 
这将是输出(请注意,解决方案不受“#”)数量的限制:


我希望它能帮助你!

awk
拯救你

我不确定这是不是最好的方式,但工作

awk    'BEGIN{d="."}
/#\.#\.#\.#/ {sub("#.#.#.#", i d a[i] d b[i d a[i]] d (++c[i d a[i] d b[i d a[i]]]))}
   /#\.#\.#/ {sub("#.#.#"  , i d a[i] d (++b[i d a[i]]))}
      /#\.#/ {sub("#.#"    , i d (++a[i]))}
         /#/ {sub("#"      , (++i))} 1'
更新:以上仅限于4个级别。这里有一个更好的,不限级别数

 awk '{d=split($1,a,"#")-1;                # find the depth
       c[d]++;                             # increase counter for current          
       for(i=pd+1;i<=d;i++) c[i]=1;        # reset when depth increases
       for(i=1;i<=d;i++) {sub(/#/,c[i])};  # replace digits one by one
       pd=d} 1'                            # set previous depth and print
awk'{d=split($1,a,“#”)-1;#查找深度
c[d]++#增加电流计数器

对于(i=pd+1;i,这里有另一种方法

代码下面提供了解释

awk 'BEGIN {n0=1; prev=0}
   {n1=split($1, elems, ".");  # Get the number of pound signs
    dif = (n1-n0);             # Increase in topic depth from previous line
    scale = (10 ^ dif);        # 10 raised to dif
    current=(int(prev*scale)+1);  # scale the number by change in depth
    withdots=gensub(/([0-9])/, "\\1." , "g", current);  # dot between digits
    {print withdots, $2 }
     n0=n1;
     prev=current}' number.txt


1) Title
2) Title
3) Title
3.1) Subtitle
3.1.1) Section
3.2) Subtitle
4) Title
将主题数字视为十进制数字。
我们通过公式
10^dif+1
从上一个数字中得到当前数字

在哪里 dif=
(从上一行增加级别数)
最初,
dif
为零,因此我们从1得到2,从2得到3,
通过
1*(10^0)+1
=
1*1+1
=
2

2*(10^0)+1
=
2*1+1
=
3

然后我们通过
3*(10^1)+1

通过
311*(10^-1)+1等从311中删除32

awk 'function w(){
    k=m>s?m:s
    for(i=1;i<=k;i++){
        if(i>m){
            a[i]=0
        }
        else{
            a[i]=(i==m)?++a[i]:a[i]   #ended "#" increase
            sub("#",a[i]=a[i]?a[i]:1) 
        }
    }
    s=m
}
{m=split($1,t,"#")-1;w()}1' file



1) Title
2) Title
3) Title
3.1) Subtitle
3.1.1) Section
3.2) Subtitle
4) Title
5) Title
5.1) Subtitle
5.1.1) Section
5.2) Subtitle
5.2.1) Section
5.2.1.1) Subsection
6) Title
7) Title
7.1) Subtitle
7.1.1) Section
7.1.1.1) Subsection
7.1.1.2) Subsection
awk'函数w(){
k=m>s?m:s
对于(i=1;im){
a[i]=0
}
否则{
a[i]=(i==m)?++a[i]:a[i]#结束“#”增加
sub(#),a[i]=a[i]?a[i]:1)
}
}
s=m
}
{m=split($1,t,“#”)-1;w()}1'文件
1) 头衔
2) 头衔
3) 头衔
3.1)副标题
3.1.1)节
3.2)副标题
4) 头衔
5) 头衔
5.1)副标题
5.1.1)节
5.2)副标题
5.2.1)节
5.2.1.1)小节
6) 头衔
7) 头衔
7.1)副标题
7.1.1)节
7.1.1.1)小节
7.1.1.2)小节

与@karakfa的方法相同(短而甜),对假设的最大子目数也有相同的警告,但略短且更有效:

awk 'BEGIN{d="."}
  /#\.#\.#\.#/ {sub("#.#.#.#", i d a d b d (++c) )}
     /#\.#\.#/ {sub("#.#.#"  , i d a d (++b) );  c=0;}
        /#\.#/ {sub("#.#"    , i d (++a));       b=0;}
           /#/ {sub("#"      , (++i));           a=0;} 1'

这是我的看法。在FreeBSD中测试过,所以我希望它在任何地方都能工作

#!/usr/bin/awk -f

BEGIN {
  depth=1;
}

$1 ~ /^#(\.#)*\)$/ {
  thisdepth=split($1, _, ".");

  if (thisdepth < depth) {
    # end of subsection, back out to current depth by deleting array values
    for (; depth>thisdepth; depth--) {
      delete value[depth];
    }
  }
  depth=thisdepth;

  # Increment value of last member
  value[depth]++;

  # And substitute it into the current line.
  for (i=1; i<=depth; i++) {
    sub(/#/, value[i], $0);
  }
}

1
为了便于阅读,也可以这样表达:

awk -vd=1 '$1~/^#(\.#)*\)$/{              # match only the lines we care about
    t=split($1,_,".");                    # this line has 't' levels
    if (t<d) for(;d>t;d--) delete v[d];   # if levels decrease, trim the array
    d=t; v[d]++;                          # reset our depth, increment last number
    for (i=1;i<=d;i++) sub(/#/,v[i],$0)   # replace hash characters one by one
  } 1'                                    # and print.
awk '{t=split($1,_,".");v[t]++;for(;d>t;d--)delete v[d];d=t;for(i=1;i<=d;i++)sub(/#/,v[i],$0)}1' file
它当然缩小成这样的一行:

awk -vd=1 '$1~/^#(\.#)*\)$/{              # match only the lines we care about
    t=split($1,_,".");                    # this line has 't' levels
    if (t<d) for(;d>t;d--) delete v[d];   # if levels decrease, trim the array
    d=t; v[d]++;                          # reset our depth, increment last number
    for (i=1;i<=d;i++) sub(/#/,v[i],$0)   # replace hash characters one by one
  } 1'                                    # and print.
awk '{t=split($1,_,".");v[t]++;for(;d>t;d--)delete v[d];d=t;for(i=1;i<=d;i++)sub(/#/,v[i],$0)}1' file
这与上面的awk脚本遵循相同的逻辑,但完全在bash中工作,使用参数扩展替换
#
字符。它所遭受的一个缺陷是,它不会在每行的第一个单词周围保留空格,因此会丢失任何缩进。通过一点工作,这也可以得到缓解


享受。

Facundo,你能以这种方式贡献你的时间真是太好了。为了保持善意和有用性,我建议你在回答中添加一些解释,这样它不仅可以作为问题中描述的一个问题的解决方案,还可以作为一种教育工具在GNU awk(gawk)中的作品,但不是OSX、FreeBSD等中的awk。
gensub
不可移植。聪明地修复阵列混乱。我认为这将是一个很好的采访问题。
awk -vd=1 '$1~/^#(\.#)*\)$/{t=split($1,_,".");if(t<d)for(;d>t;d--)delete v[d];d=t;v[d]++;for(i=1;i<=d;i++)sub(/#/,v[i],$0)}1'
awk -vd=1 '$1~/^#(\.#)*\)$/{              # match only the lines we care about
    t=split($1,_,".");                    # this line has 't' levels
    if (t<d) for(;d>t;d--) delete v[d];   # if levels decrease, trim the array
    d=t; v[d]++;                          # reset our depth, increment last number
    for (i=1;i<=d;i++) sub(/#/,v[i],$0)   # replace hash characters one by one
  } 1'                                    # and print.
awk '{
    t=split($1,_,".");                  # get current depth
    v[t]++;                             # increment counter for depth
    for(;d>t;d--) delete v[d];          # delete record for previous deeper counters
    d=t;                                # record current depth for next round
    for (i=1;i<=d;i++) sub(/#/,v[i],$0) # replace hashes as required.
  } 1'
awk '{t=split($1,_,".");v[t]++;for(;d>t;d--)delete v[d];d=t;for(i=1;i<=d;i++)sub(/#/,v[i],$0)}1' file