How to store file information into an array?

With this part of script I can get a necessary information about files in my directory(and subdirectories). The only information I need is the extension and the size of file.

for file in `find . -type f`; do size=$(stat -c '%s' ${file}) file=$(echo "${file}" | awk -F/ '{print $NF}') ext=$(echo "${file}" | grep '..*\.' | awk -F. '{print $NF}' | grep '[A-Za-z0-9]')
if [ -z ${ext} ]; then echo "NOTE: no extention"
else EXTS="${EXTS}${ext}${newLine}"

It is only part of the script. So my question is: How can I put this informarion into an array? I mean I want an array with elements to look like this:

 c/123 /12 h/90 /0 txt/0

where c, h and txt are file extension and 123, 12 and 0 are file sizes. So lately I can separately work with sizes and extensions
I hope, I've neatly put my question down. Sorry for mistakes. :)

1

2 Answers

First, don't do for file in $(find …). That's very fragile.

Now, you can simplify your code a bit by getting find to print the filenames and sizes together, using -printf:

find . -type f -printf '%s.%f/'

Then, you can use awk to process this output to get cumulative sizes by extension. Note that I used . to separate the filename (%f) from the size (%s), and I added a / after that. Hence, I can use . as a field separator in awk. And since the only characters not allowed in filenames are / and the ASCII NUL, I can safely use / as the record separator.

So:

awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next} {size["/"] += $1}
END {for (i in size) {print i,"/",size[i]}'

Here, I'm using / as the index if there's no extension.

Combined:

$ find . -type f -printf '%s.%f/' | awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next}
{size["/"] += $1}
END {for (i in size) {printf "%s/%d\n", i, size[i]}}'
h/780
md/2509
tex/23961
c/13557
//5109
txt/2349291
sh/1166
py/12248

Now, if your extensions don't contain spaces, you could just do:

my_array=( $(find . -type f -printf '%s.%f/' | awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next} {size["/"] += $1} END {for (i in size) {printf "%s/%d\n", i, size[i]}}') )

Or, you can use process substitution and read each entry in:

my_arr=()
while IFS='' read -r entry
do my_arr+=( "$entry" )
done < <(find . -type f -printf '%s.%f/' | awk -F. -v RS=/ 'NF > 2 {size[$NF] += $1; next} {size["/"] += $1} END {for (i in size) {printf "%s/%d\n", i, size[i]}}')

As before:

$ printf "%s\n" "${my_arr[@]}"
h/780
md/2509
tex/23961
c/13557
//5109
txt/2349291
sh/1166
py/12248

Here is a short bash script what is doing the job:

i=0
while read -r -d $'\0' file
do size=$(stat -c '%s' ${file}) ext=`basename $file | sed -re "s/^[^.]+.*\.//"` if [ -z "$ext" ] || [ "$ext" = "`basename $file`" ] ; then echo "NOTE: no extention ($file)" else extensions[$i]="$ext" sizes[$((i++))]=$size fi
done < <(find . -type f -print0)
for (( j=0 ; j<i; j++ )) do echo index: $j / extension: ${extensions[$j]} / size: ${sizes[$j]}
done
2

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like