Bash 缩进线(树)到类路径线

Bash 缩进线(树)到类路径线,bash,recursion,tree,Bash,Recursion,Tree,我有如下结构的输入文件: a1 b1 c1 c2 c3 b2 c1 d1 d2 b3 b4 a2 a3 b1 b2 c1 c2 a1 b1 c1 a1 b1 a1 DD: line 8: [0-1]: bad array subscript 每个级别缩进2个空格。所需的输出是: a1/b1/c1 a1/b1/c2 a1/b1/c3 a1/b2/c1/d1 a1/b2/c1/d2 a1/b3 a1

我有如下结构的输入文件:

a1
  b1
    c1
    c2
    c3
  b2
    c1
      d1
      d2
  b3
  b4
a2
a3
  b1
  b2
    c1
    c2
a1 b1 c1
a1 b1
a1

DD: line 8: [0-1]: bad array subscript
每个级别缩进2个空格。所需的输出是:

a1/b1/c1
a1/b1/c2
a1/b1/c3
a1/b2/c1/d1
a1/b2/c1/d2
a1/b3
a1/b4
a2
a3/b1
a3/b2/c1
a3/b2/c2
它就像一个文件系统,如果下一行有更大的缩进,那么当前一行就像一个“目录”,当缩进相同时,它就像一个“文件”。需要打印“文件”的完整路径

试图在没有任何高级语言的情况下解决这个问题,比如
python
perl
——只使用基本的bash命令

我目前的代码/想法是基于递归函数调用和使用堆栈,但在“逻辑”方面存在问题。代码当前输出下一个:

a1
  b1
    c1
    c2
    c3
  b2
    c1
      d1
      d2
  b3
  b4
a2
a3
  b1
  b2
    c1
    c2
a1 b1 c1
a1 b1
a1

DD: line 8: [0-1]: bad array subscript
只有第1行是正确的-因此处理递归是错误的

input="ifile.tree"

#stack array
declare -a stack

#stack manipulation
pushstack() { stack+=("$1"); }
popstack() { unset stack[${#stack[@]}-1]; }
printstack() { echo "${stack[*]}"; }

#recursive function
checkline() {
    local uplev=$1

    #read line - if no more lines - print the stack and return
    read -r level text || (printstack; exit 1) || return

    #if the current line level is largest than previous level
    if [[ $uplev < $level ]]
    then
        pushstack "$text"
        checkline $level    #recurse
    fi

    printstack
    popstack
}

# MAIN PROGRAM

# change the input from indented spaces to
# level_number<space>text
(
    #subshell - change IFS
    IFS=,
    while read -r spaces content
    do
        echo $(( (${#spaces} / 2) + 1 )) "$content"
    done < <(sed 's/[^ ]/,&/' < "$input")

) | (   #pipe to another subshell
    checkline 0 #recurse by levels
)
input=“ifile.tree”
#堆栈阵列
声明-堆栈
#堆栈操作
pushstack(){stack+=(“$1”);}
popstack(){unset stack[${#stack[@]}-1];}
printstack(){echo“${stack[*]}”;}
#递归函数
对勾线(){
本地价格=1美元
#读取行-如果没有更多行-打印堆栈并返回
读取-r级别文本| |(打印堆栈;退出1)| |返回
#如果当前行级别比上一级别最大
如果[[$uplev<$level]]
然后
pushstack“$text”
检查行$level#递归
fi
打印堆栈
爆米花
}
#主程序
#将输入从缩进空格更改为
#级别编号text
(
#子shell-更改IFS
如果=,
而read-r则用于分隔内容
做
echo$((${spaces}/2)+1))“$content”
完成了一个有趣的问题

此awk(可以是一行程序)命令执行以下任务:

awk -F'  ' 'NF<=p{for(i=1;i<=p;i++)printf "%s%s", a[i],(i==p?RS:"/")
            if(NF<p)for(i=NF;i<=p;i++) delete a[i]}
            {a[NF] =$NF;p=NF }
            END{for(i=1;i<=NF;i++)printf "%s%s", a[i],(i==NF?RS:"/")}' file

awk-F''NF我最近不得不做一些类似的事情,通过一些调整,我可以在这里发布我的脚本:

#!/bin/bash

prev_level=-1
# Index into node array
i=0

# Regex to screen-scrape all nodes
tc_re="^((  )*)(.*)$"
while IFS= read -r ln; do
    if  [[ $ln =~ $tc_re ]]; then
        # folder level indicated by spaces in preceding node name
        spaces=${#BASH_REMATCH[1]}
        # 2 space characters per level
        level=$(($spaces / 2))
        # Name of the folder or node
        node=${BASH_REMATCH[3]}        
        # get the rest of the node path from the previous entry
        curpath=( ${curpath[@]:0:$level} $node )

        # increment i only if the current level is <= the level of the previous
        # entry
        if [ $level -le $prev_level ]; then
            ((i++))
        fi

        # add this entry (overwrite previous if $i was not incremented)
        tc[$i]="${curpath[@]}"

        # save level for next iteration
        prev_level=$level
    fi
done

for p in "${tc[@]}"; do
    echo "${p// //}"
done
!/bin/bash
上一级=-1
#索引到节点数组中
i=0
#正则表达式用于筛选所有节点
tc_re=“^(()*)(*)”
当IFS=read-r ln;do
如果[[$ln=~$tc\u re]];那么
#由前面节点名称中的空格指示的文件夹级别
空格=${BASH#u重新匹配[1]}
#每级2个空格字符
级别=$($spaces/2))
#文件夹或节点的名称
node=${BASH_重新匹配[3]}
#从上一个条目获取节点路径的其余部分
curpath=(${curpath[@]:0:$level}$node)

#仅当当前级别是放弃easy way并寻找
解决此问题的关键,而不使用任何高级语言(如python、perl),只使用基本的bash命令时,才增加i。
仅为练习设置限制。@BMW不理解您的观点。Simple既没有
perl
也没有
python
而且我不知道awk。所以尝试用我所知道和拥有的工具来解决这个问题。这有什么问题吗?如果你能帮我解决
awk
问题,我会很高兴的……为什么投票结果如此接近?@cajwine你没有提到awk是“不允许的”在你的问题中,我还看到你在脚本中使用了
sed
。我想我的awk答案不会被列入“黑名单”,对吗?)@Kent当然,awk如果好的话(正如我记得你通常使用的awk解决方案,最多60个字符…;)这是难以置信的优雅。没有任何复杂的递归。谢谢。:)正如我上面所说的那样非常紧凑,做应该做的事情。必须学习awk,它真的很强大。老实说,有一个问题(还没有理解),但承诺——会学到的。:)