Search code examples
bashshellawkls

ls command and size of files in shell script


count=0;      #count for counting
IFS='
'
for x in `ls -l $input`;     #for loop using ls command
do 
a=$(ls -ls | awk '{print $6}')   #print[6] is sizes of  file
echo $a

b=`echo $a | awk '{split($0,numbers," "); print numbers[1]}'`
echo $b     
if [ $b -eq 0 ]          # b is only  size of a file
then
count=`expr $count + 1`   #if b is zero , the count will increase one by one
fi
echo $count
done

I want to find 0 size files . I do that using find command. The second thing is I want to count number of has 0 size of files using ls command and awk. But It doesn't true code . What is my mistake ?


Solution

  • Your main mistake is that you're parsing ls!

    If you want to find (regular) files that are empty, and if you have a version of find that supports the -empty predicate, use it:

    find . -type f -empty
    

    Note that this will recurse in subfolders too; if you don't want that, use:

    find . -maxdepth 1 -type f -empty
    

    (assuming that your find also supports -maxdepth).

    If you only want to count how many empty (regular) files you have:

    find . -maxdepth 1 -type f -empty -printf x | wc -m
    

    and if you want to perform both operations at the same time, i.e., print out the name or save them in an array for future use, and count them:

    empty_files=()
    while IFS= read -r -d '' f; do
        empty_files+=( "$f" )
    done < <(find . -maxdepth 1 -type f -empty -print0)
    printf 'There are %d empty files:\n' "${#empty_files[@]}"
    printf '   %s\n' "${empty_files[@]}"
    

    With Bash≥4.4, you could use mapfile instead of the while-read loop:

    mapfile -t -d '' empty_files < <(find . -maxdepth 1 -type f -empty -print0)
    printf 'There are %d empty files:\n' "${#empty_files[@]}"
    printf '   %s\n' "${empty_files[@]}"
    

    For a POSIX-compliant way, use test with the -s option:

    find . -type f \! -exec test -s {} \; -print
    

    and if you don't want to recurse into subdirectories, you'll have to -prune them:

    find . \! -name . -prune -type f \! -exec test -s {} \; -print
    

    and if you want to count them:

    find . \! -name . -prune -type f \! -exec test -s {} \; -exec printf x | wc -m
    

    and here, if you want to perform both operations (count them and save them in an array for later use), use the previous while-read loop (or mapfile if you live in the future) with this find:

    find . \! -name . -prune -type f \! -exec test -s {} \; -exec printf '%s\0' {} \;
    

    Also see chepner's answer for a pure shell solution (needs minor tweaking to be POSIX compliant).


    Regarding your comment

    I want to count and delete [empty files]. How can I do that at the same time?

    If you have GNU find (or a find that supports all the goodies):

    find . -maxdepth 1 -type f -empty -printf x -delete | wc -m
    

    if not,

    find . \! -name . -prune -type f \! -exec test -s {} \; -printf x -exec rm {} \; | wc -m
    

    Make sure that the -delete (or -exec rm {} \;) predicate is at the end! do not exchange the order of the predicates!