Reputation: 12371
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?
Upvotes: 2
Views: 3217
Reputation: 302
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
Upvotes: 2
Reputation: 7627
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.
Upvotes: 4
Reputation: 74645
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.
Upvotes: 3