Sunday, 15 May 2011

bash - Indented lines (tree) to path-like lines -



bash - Indented lines (tree) to path-like lines -

i have input files construction next:

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

each level indented 2 spaces. needed output is:

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

it filesystem, if next line have bigger indentation, current 1 "directory" , when have same indentation "file". need print total paths of "files".

trying solve without high-level language, python, perl - basic bash commands.

my current code/idea based on recursive function phone call , working stack, have problem "logic". code outputs next:

a1 b1 c1 a1 b1 a1 dd: line 8: [0-1]: bad array subscript

only 1st line ok - handling recursion wrong...

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 stack , homecoming read -r level text || (printstack; exit 1) || homecoming #if current line level largest previous level if [[ $uplev < $level ]] pushstack "$text" checkline $level #recurse fi printstack popstack } # main programme # alter input indented spaces # level_number<space>text ( #subshell - alter ifs ifs=, while read -r spaces content echo $(( (${#spaces} / 2) + 1 )) "$content" done < <(sed 's/[^ ]/,&/' < "$input") ) | ( #pipe subshell checkline 0 #recurse levels )

sry long code - can help?

interesting question.

this awk (could one-liner) command job:

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

you can see above, there duplicated codes, can extract them function if like.

test data:

kent$ cat f a1 b1 c1 c2 c3 b2 c1 d1 d2 b3 b4 a2 a3 b1 b2 c1 c2 kent$ 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:"/")} ' f 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

bash recursion tree

No comments:

Post a Comment