Velvet Star Monitor

Standout celebrity highlights with iconic style.

general

bash script: calculate sum size of files

Writer Andrew Henderson

I'm working on Linux and need to calculate the sum size of some files in a directory.

I've written a bash script named cal.sh as below:

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do echo $line
done<`ls -l | grep opencv | awk '{print $5}'`

However, when I executed this script ./cal.sh, I got an error:

./cal.sh: line 6: `ls -l | grep opencv | awk '{print $5}'`: ambiguous redirect

And if I execute it with sh cal.sh, it seems to work but I will get some weird message at the end of output:

25
31
385758: File name too long

Why does sh cal.sh seem to work? Where does File name too long come from?

3 Answers

Alternatively, you can do:

du -cb *opencv* | awk 'END{print $1}'

option -b will display each file in bytes and -c will print the total size.

I would recommend against using that pipeline to get the sizes of the files you want - in general parsing ls is something that you should avoid. Instead, you can just use *opencv* to get the files and stat to print the size:

stat -c %s *opencv*

The format specifier %s prints the size of each file in bytes.

You can pipe this to awk to get the sum:

stat -c %s *opencv* | awk '{ sum += $0 } END { if (sum) print sum }'

The if is there to ensure that no input => no output.

Ultimately, as other answers will point out, it's not a good idea to parse the output of ls because it may vary between systems. But it's worth knowing why the script doesn't work.

The ambiguous redirect error is because you need quotes around your ls command i.e.:

while IFS='' read -r line || [[ -n "$line" ]]; do echo $line
done < "`ls -l | grep opencv | awk '{print $5}'`"

But this still doesn't do what you want. The "<" operator is expecting a filename, which is being defined here as the output of the ls command. But you don't want to read a file, you want to read the output of ls. For that you can use the "<<<" operator, also known as a "here string" i.e.:

while IFS='' read -r line || [[ -n "$line" ]]; do echo $line
done <<< "`ls -l | grep opencv | awk '{print $5}'`"

This works as expected, but has some drawbacks. When using a "here string" the command must first execute in full, then store the output of said command in a temporary variable. This can be a problem if the command takes long to execute or has a large output.

IMHO the best and most standard method of iterating a commands output line by line is the following:

ls -l | grep opencv | awk '{print $5} '| while read -r line ; do echo "line: $line"
done

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 and acknowledge that you have read and understand our privacy policy and code of conduct.