#!/usr/bin/sh entry_length () { echo '05' } entry_ndx () { echo "$(entry_length)*${01}+${02}" } entry_size_ndx () { entry_ndx "${01}" '0' } entry_name_ndx () { entry_ndx "${01}" '01' } entry_bottom_ndx () { entry_ndx "${01}" '02' } entry_top_ndx () { entry_ndx "${01}" '03' } entry_par_ndx () { entry_ndx "${01}" '04' } entry_name () { echo "${entries[$(entry_name_ndx "${01}")]}" } entry_size () { echo "${entries[$(entry_size_ndx "${01}")]}" } entry_par () { echo "${entries[$(entry_par_ndx "${01}")]}" } entry_range () { echo\ "${entries[$(entry_bottom_ndx "${01}")]}"\ "${entries[$(entry_top_ndx "${01}")]}" } entry_by_name () { let pos="$(entry_ndx "${02}" '01')" while [[ "${pos}" -lt "${03}" ]] do [[ "${entries[${pos}]}" == "${01}" ]] && echo "${pos}-01" let pos+="$(entry_length)" done } entry_by_name_s () { echo >&2 "EBN $*" let bottom="${02}" top="${03}" # echo >&2 "${top}" if [[ "${01}" < "$(entry_name "${bottom}")" ]] then echo "02*${bottom}-01" else while [[ "${top}" -gt "${bottom}" ]] do let mid="(${top}+${bottom})/02" name="$(entry_name "${mid}")" # echo >&2 "?${name}" if [[ "${name}" == "${01}" ]] then echo "02*${mid}" return elif [[ "${01}" < "${name}" ]] then let top="${mid}" else let bottom="${mid}+01" fi done echo "02*${top}-01" fi } resolve () { echo >&2 "resolve $*" while let "${#}" do if [[ "${01}" == '.' ]] then let top='0' else let top="$(entry_by_name_s "${01}" $(entry_range "${top}"))" fi let "${top}&01" && { echo >&2 "${01}: Path not found." exec false } let top="${top}/02" echo "${top}" # entry_by_name_s "${01}" shift done } update_sizes () { let size="${01}" while shift do let entries[$(entry_size_ndx "${01}")]+="${size}" done } # line 0 is reserved for the root directory # the root directory is not present in the listing let line='01' # we start in the root directory path=(0) # we expect the listing to be in Latin-2 character set iconv '-f' 'latin2' '-t' 'utf8' "${01}" | { while read && [[ "${REPLY:0:6}" == 'total ' ]] # the first line of a directory listing is total # do # remember where the current directory starts unset prev_name && let par="${path[${#path[@]}-01]}" first="${line}" && while read inode rights links owner group size month day time name && [[ -n "${name}" ]] # the trailing blank line will be skipped do [[ "${name}" > "${prev_name}" ]] || # input error: unsorted { echo >&2 'Decreasing' exec false } # remember for the next cycle prev_name="${name}" # store data let entries[$(entry_size_ndx "${line}")]="${size}" entries[$(entry_name_ndx "${line}")]="${name}" let entries[$(entry_par_ndx "${line}")]="${par}" update_sizes "${size}" "${path[@]}" let line="${line}"'+01' done # store directory let entries[$(entry_bottom_ndx "${par}")]="${first}" let entries[$(entry_top_ndx "${par}")]="${line}" # echo "${line}" "${#entries[@]}" # parse the following path read && [[ "${REPLY:${#REPLY}-01}" == ':' ]] && IFS='/' read -a path <<<"${REPLY:0:${#REPLY}-01}" && path=($(resolve "${path[@]}")) echo "${path[@]}" # report total # entry_name 05 # for now # break done && # entry_size '0' { let ndx='0' while [[ "${ndx}" -lt "${line}" ]] do echo "$(entry_size "${ndx}")" "${ndx}" let ndx+='1' done } | sort '-n' | while read total pos do echo "${total}" "${pos}" "$(entry_par "${pos}")" "$(entry_name "${pos}")" done }