Bash Script: Calculate Sum Size of Files

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

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.

Alexander Ross

Alexander Ross

Gaming, Esports & Interactive Media Writer

Alexander Ross has covered the video game industry for a decade, writing deep dives on game design, esports tournaments, VR developments, and gaming culture.

Share this article
Twitter Facebook Pinterest