How do I write a script to count the total number of files, and directories in my home directory then display...












3















I want to do it with a for loop. This is what I've come up with so far which does not work.



for home in /home/ {.,/}*; do echo "$home"; done


I would like to do this non-recursively if possible.










share|improve this question

























  • Interesting question. My first thought is that it's not possible, but I'm not sure. If it is possible it's a lot more difficult non-recursively. So much more difficult that for any tree structure traversal, recursion is the only way I can remember seeing it done.

    – RobertL
    Nov 10 '15 at 0:39











  • Well I suppose a recursive method would work too. What do you have in mind?

    – David Prentice
    Nov 10 '15 at 1:59











  • Since it changed, I'm editing your Title and Question a little.

    – RobertL
    Nov 10 '15 at 2:31











  • How about find ~ | wc-l ?

    – Jeff Schaller
    Nov 10 '15 at 3:40






  • 1





    Please don't. Using the shell for this is much harder than it needs to be, very fragile and easy to get wrong, and orders of magnitude slower than using find.

    – terdon
    Nov 10 '15 at 11:50


















3















I want to do it with a for loop. This is what I've come up with so far which does not work.



for home in /home/ {.,/}*; do echo "$home"; done


I would like to do this non-recursively if possible.










share|improve this question

























  • Interesting question. My first thought is that it's not possible, but I'm not sure. If it is possible it's a lot more difficult non-recursively. So much more difficult that for any tree structure traversal, recursion is the only way I can remember seeing it done.

    – RobertL
    Nov 10 '15 at 0:39











  • Well I suppose a recursive method would work too. What do you have in mind?

    – David Prentice
    Nov 10 '15 at 1:59











  • Since it changed, I'm editing your Title and Question a little.

    – RobertL
    Nov 10 '15 at 2:31











  • How about find ~ | wc-l ?

    – Jeff Schaller
    Nov 10 '15 at 3:40






  • 1





    Please don't. Using the shell for this is much harder than it needs to be, very fragile and easy to get wrong, and orders of magnitude slower than using find.

    – terdon
    Nov 10 '15 at 11:50
















3












3








3


2






I want to do it with a for loop. This is what I've come up with so far which does not work.



for home in /home/ {.,/}*; do echo "$home"; done


I would like to do this non-recursively if possible.










share|improve this question
















I want to do it with a for loop. This is what I've come up with so far which does not work.



for home in /home/ {.,/}*; do echo "$home"; done


I would like to do this non-recursively if possible.







shell shell-script directory home






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Feb 15 at 5:39









Rui F Ribeiro

40.7k1479137




40.7k1479137










asked Nov 10 '15 at 0:05









David PrenticeDavid Prentice

2491518




2491518













  • Interesting question. My first thought is that it's not possible, but I'm not sure. If it is possible it's a lot more difficult non-recursively. So much more difficult that for any tree structure traversal, recursion is the only way I can remember seeing it done.

    – RobertL
    Nov 10 '15 at 0:39











  • Well I suppose a recursive method would work too. What do you have in mind?

    – David Prentice
    Nov 10 '15 at 1:59











  • Since it changed, I'm editing your Title and Question a little.

    – RobertL
    Nov 10 '15 at 2:31











  • How about find ~ | wc-l ?

    – Jeff Schaller
    Nov 10 '15 at 3:40






  • 1





    Please don't. Using the shell for this is much harder than it needs to be, very fragile and easy to get wrong, and orders of magnitude slower than using find.

    – terdon
    Nov 10 '15 at 11:50





















  • Interesting question. My first thought is that it's not possible, but I'm not sure. If it is possible it's a lot more difficult non-recursively. So much more difficult that for any tree structure traversal, recursion is the only way I can remember seeing it done.

    – RobertL
    Nov 10 '15 at 0:39











  • Well I suppose a recursive method would work too. What do you have in mind?

    – David Prentice
    Nov 10 '15 at 1:59











  • Since it changed, I'm editing your Title and Question a little.

    – RobertL
    Nov 10 '15 at 2:31











  • How about find ~ | wc-l ?

    – Jeff Schaller
    Nov 10 '15 at 3:40






  • 1





    Please don't. Using the shell for this is much harder than it needs to be, very fragile and easy to get wrong, and orders of magnitude slower than using find.

    – terdon
    Nov 10 '15 at 11:50



















Interesting question. My first thought is that it's not possible, but I'm not sure. If it is possible it's a lot more difficult non-recursively. So much more difficult that for any tree structure traversal, recursion is the only way I can remember seeing it done.

– RobertL
Nov 10 '15 at 0:39





Interesting question. My first thought is that it's not possible, but I'm not sure. If it is possible it's a lot more difficult non-recursively. So much more difficult that for any tree structure traversal, recursion is the only way I can remember seeing it done.

– RobertL
Nov 10 '15 at 0:39













Well I suppose a recursive method would work too. What do you have in mind?

– David Prentice
Nov 10 '15 at 1:59





Well I suppose a recursive method would work too. What do you have in mind?

– David Prentice
Nov 10 '15 at 1:59













Since it changed, I'm editing your Title and Question a little.

– RobertL
Nov 10 '15 at 2:31





Since it changed, I'm editing your Title and Question a little.

– RobertL
Nov 10 '15 at 2:31













How about find ~ | wc-l ?

– Jeff Schaller
Nov 10 '15 at 3:40





How about find ~ | wc-l ?

– Jeff Schaller
Nov 10 '15 at 3:40




1




1





Please don't. Using the shell for this is much harder than it needs to be, very fragile and easy to get wrong, and orders of magnitude slower than using find.

– terdon
Nov 10 '15 at 11:50







Please don't. Using the shell for this is much harder than it needs to be, very fragile and easy to get wrong, and orders of magnitude slower than using find.

– terdon
Nov 10 '15 at 11:50












3 Answers
3






active

oldest

votes


















1














There are many higher level commands that will almost do what you want to do, but this is a good demonstration of how to do the same thing in a shell script. This should work on any system that has /bin/sh. It's not dependent on any other commands.



You can save this script as any filename, and then type sh ./whatever_you_named_it to execute it.



I've split this into two sections, Listing the Files, and Counting the Files. Listing the files recursively is the most complicated, but once we have a list, it's easy to count them.



Listing the Files



This script recursively lists all of the files and directories under your home directory or a directory it receives as a parameter. With no parameters, it defaults to the home directory.



#!/bin/sh

if test $# -eq 0
then
startdir="$HOME"
else
startdir="$1"
fi

for f in "$start"/* # step through all files in the starting directory
do
echo "$f" # print the file name
if test -d "$f" # is the file a directory? (-d)
then
sh "$0" "$f" # yes call this script with the dir as arg
fi
done


Let's discuss each step:





  1. If no parameters were passed to the script, then use "$HOME" as the starting directory, otherwise use the first parameter. ($# contains the number of parameters passed to this script and we use the shell's built-in test command to find out if it's zero):



    if test $# -eq 0
    then
    startdir="$HOME"
    else
    startdir="$1"
    fi



  2. Iterate over files in your home directory. "$HOME"/* expands to all of the non-hidden files and directories at the top level of your home directory:



    for f in "$HOME"/*
    do



  3. Print the file name. I think you know echo:



         echo "$f"               # print the file name



  4. Call the shell built-in test command with the -d option. test returns true if the argument, "$f", is a directory. This is most often written as [ -d "$f" ] for brevity, but it really is a command. [Search for "test expr" in the sh man page]:



        if test -d "$f"         # is the file a directory? (-d)
    then



  5. This next statement is where we recur. We start a new copy of the currently running script and pass a the current "$f" directory name to it. The $0 expands to the filename of the current shell script. Rather than type some filename here, we use $0 so this script will work even if it's name is changed. For example, if the script was called rlist, then you could also write sh rlist "$f", but if the script was renamed, the script would no longer function correctly, because it would be calling a non-existent script, or the wrong script. [See "Special Parameters" in the sh man page]:



            sh "$0" "$f"         # yes call this script with the dir as arg



  6. Terminates the if statement and the for loop.



         fi
    done



Counting the Files



The script so far lists the files but does not count them. If you want to get a count of all the files and directories execute this:



sh ./scriptname | wc -l


wc -l is the "word count" command, and with the -l option counts only the lines. The above pipeline prints a number which is the number of files under your home directory.






share|improve this answer


























  • you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

    – mikeserv
    Nov 10 '15 at 6:10













  • @mikeserv All true, but way beyond the level of understanding of the questioner.

    – RobertL
    Nov 10 '15 at 6:12











  • Let us continue this discussion in chat.

    – RobertL
    Nov 10 '15 at 6:17











  • @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

    – RobertL
    Nov 10 '15 at 19:39











  • @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

    – RobertL
    Nov 10 '15 at 19:41



















3














with find for not directory types in the current directory without recursing:



find . ! -name . -prune ! -type d | grep -c /


...for only directories drop the second bang, or for all filetypes drop the -type test entirely.



that's easy in this case because without recursion we only ever see one path delimiter per file and so there is no confusion about what and where to count. counting newlines when you should be counting files can lead to trouble - the two things are unrelated. so what to do otherwise?



find .//. | grep -c '^.//.'


...will return an accurate count of child objects + this object rooted in the current directory.



equally as valid, but with reversed logic because it quotes newlines internally and probably faster because it needs only to stat() each directory rather than every constituent file:



ls -1qRA . | grep -Exc [^/]+


if you drop the -R option to ls it will work without recursion just as well.



it is possible, though, that the above could return a false count depending on multibyte characters in filenames and incompatible locale settings. putting LC_ALL=C in a POSIX-conformant ls's environment would protect against that, and for depth counts of a sizable tree, doing so can only help matters with regards to performance after all.






share|improve this answer

































    0














    Use find:



    When you say non-recursively, did you mean that you only want a count of files/directories in /home, but not any subdirectories? If that is the case, you can restrict results to the top level with the maxdepth option.



    find /home -maxdepth 1 | wc -l


    Using for:



    i=0; for home in ~/*; do (( i++ )); done; echo $i


    Note the spaces between the double parentheses and the enclosed i++.






    share|improve this answer


























    • Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

      – terdon
      Nov 10 '15 at 11:50











    • @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

      – Nigel Tufnel
      Nov 10 '15 at 14:37











    • Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

      – terdon
      Nov 10 '15 at 14:43













    • are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

      – mikeserv
      Nov 10 '15 at 17:42











    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "106"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: false,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f242002%2fhow-do-i-write-a-script-to-count-the-total-number-of-files-and-directories-in-m%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    There are many higher level commands that will almost do what you want to do, but this is a good demonstration of how to do the same thing in a shell script. This should work on any system that has /bin/sh. It's not dependent on any other commands.



    You can save this script as any filename, and then type sh ./whatever_you_named_it to execute it.



    I've split this into two sections, Listing the Files, and Counting the Files. Listing the files recursively is the most complicated, but once we have a list, it's easy to count them.



    Listing the Files



    This script recursively lists all of the files and directories under your home directory or a directory it receives as a parameter. With no parameters, it defaults to the home directory.



    #!/bin/sh

    if test $# -eq 0
    then
    startdir="$HOME"
    else
    startdir="$1"
    fi

    for f in "$start"/* # step through all files in the starting directory
    do
    echo "$f" # print the file name
    if test -d "$f" # is the file a directory? (-d)
    then
    sh "$0" "$f" # yes call this script with the dir as arg
    fi
    done


    Let's discuss each step:





    1. If no parameters were passed to the script, then use "$HOME" as the starting directory, otherwise use the first parameter. ($# contains the number of parameters passed to this script and we use the shell's built-in test command to find out if it's zero):



      if test $# -eq 0
      then
      startdir="$HOME"
      else
      startdir="$1"
      fi



    2. Iterate over files in your home directory. "$HOME"/* expands to all of the non-hidden files and directories at the top level of your home directory:



      for f in "$HOME"/*
      do



    3. Print the file name. I think you know echo:



           echo "$f"               # print the file name



    4. Call the shell built-in test command with the -d option. test returns true if the argument, "$f", is a directory. This is most often written as [ -d "$f" ] for brevity, but it really is a command. [Search for "test expr" in the sh man page]:



          if test -d "$f"         # is the file a directory? (-d)
      then



    5. This next statement is where we recur. We start a new copy of the currently running script and pass a the current "$f" directory name to it. The $0 expands to the filename of the current shell script. Rather than type some filename here, we use $0 so this script will work even if it's name is changed. For example, if the script was called rlist, then you could also write sh rlist "$f", but if the script was renamed, the script would no longer function correctly, because it would be calling a non-existent script, or the wrong script. [See "Special Parameters" in the sh man page]:



              sh "$0" "$f"         # yes call this script with the dir as arg



    6. Terminates the if statement and the for loop.



           fi
      done



    Counting the Files



    The script so far lists the files but does not count them. If you want to get a count of all the files and directories execute this:



    sh ./scriptname | wc -l


    wc -l is the "word count" command, and with the -l option counts only the lines. The above pipeline prints a number which is the number of files under your home directory.






    share|improve this answer


























    • you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

      – mikeserv
      Nov 10 '15 at 6:10













    • @mikeserv All true, but way beyond the level of understanding of the questioner.

      – RobertL
      Nov 10 '15 at 6:12











    • Let us continue this discussion in chat.

      – RobertL
      Nov 10 '15 at 6:17











    • @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

      – RobertL
      Nov 10 '15 at 19:39











    • @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

      – RobertL
      Nov 10 '15 at 19:41
















    1














    There are many higher level commands that will almost do what you want to do, but this is a good demonstration of how to do the same thing in a shell script. This should work on any system that has /bin/sh. It's not dependent on any other commands.



    You can save this script as any filename, and then type sh ./whatever_you_named_it to execute it.



    I've split this into two sections, Listing the Files, and Counting the Files. Listing the files recursively is the most complicated, but once we have a list, it's easy to count them.



    Listing the Files



    This script recursively lists all of the files and directories under your home directory or a directory it receives as a parameter. With no parameters, it defaults to the home directory.



    #!/bin/sh

    if test $# -eq 0
    then
    startdir="$HOME"
    else
    startdir="$1"
    fi

    for f in "$start"/* # step through all files in the starting directory
    do
    echo "$f" # print the file name
    if test -d "$f" # is the file a directory? (-d)
    then
    sh "$0" "$f" # yes call this script with the dir as arg
    fi
    done


    Let's discuss each step:





    1. If no parameters were passed to the script, then use "$HOME" as the starting directory, otherwise use the first parameter. ($# contains the number of parameters passed to this script and we use the shell's built-in test command to find out if it's zero):



      if test $# -eq 0
      then
      startdir="$HOME"
      else
      startdir="$1"
      fi



    2. Iterate over files in your home directory. "$HOME"/* expands to all of the non-hidden files and directories at the top level of your home directory:



      for f in "$HOME"/*
      do



    3. Print the file name. I think you know echo:



           echo "$f"               # print the file name



    4. Call the shell built-in test command with the -d option. test returns true if the argument, "$f", is a directory. This is most often written as [ -d "$f" ] for brevity, but it really is a command. [Search for "test expr" in the sh man page]:



          if test -d "$f"         # is the file a directory? (-d)
      then



    5. This next statement is where we recur. We start a new copy of the currently running script and pass a the current "$f" directory name to it. The $0 expands to the filename of the current shell script. Rather than type some filename here, we use $0 so this script will work even if it's name is changed. For example, if the script was called rlist, then you could also write sh rlist "$f", but if the script was renamed, the script would no longer function correctly, because it would be calling a non-existent script, or the wrong script. [See "Special Parameters" in the sh man page]:



              sh "$0" "$f"         # yes call this script with the dir as arg



    6. Terminates the if statement and the for loop.



           fi
      done



    Counting the Files



    The script so far lists the files but does not count them. If you want to get a count of all the files and directories execute this:



    sh ./scriptname | wc -l


    wc -l is the "word count" command, and with the -l option counts only the lines. The above pipeline prints a number which is the number of files under your home directory.






    share|improve this answer


























    • you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

      – mikeserv
      Nov 10 '15 at 6:10













    • @mikeserv All true, but way beyond the level of understanding of the questioner.

      – RobertL
      Nov 10 '15 at 6:12











    • Let us continue this discussion in chat.

      – RobertL
      Nov 10 '15 at 6:17











    • @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

      – RobertL
      Nov 10 '15 at 19:39











    • @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

      – RobertL
      Nov 10 '15 at 19:41














    1












    1








    1







    There are many higher level commands that will almost do what you want to do, but this is a good demonstration of how to do the same thing in a shell script. This should work on any system that has /bin/sh. It's not dependent on any other commands.



    You can save this script as any filename, and then type sh ./whatever_you_named_it to execute it.



    I've split this into two sections, Listing the Files, and Counting the Files. Listing the files recursively is the most complicated, but once we have a list, it's easy to count them.



    Listing the Files



    This script recursively lists all of the files and directories under your home directory or a directory it receives as a parameter. With no parameters, it defaults to the home directory.



    #!/bin/sh

    if test $# -eq 0
    then
    startdir="$HOME"
    else
    startdir="$1"
    fi

    for f in "$start"/* # step through all files in the starting directory
    do
    echo "$f" # print the file name
    if test -d "$f" # is the file a directory? (-d)
    then
    sh "$0" "$f" # yes call this script with the dir as arg
    fi
    done


    Let's discuss each step:





    1. If no parameters were passed to the script, then use "$HOME" as the starting directory, otherwise use the first parameter. ($# contains the number of parameters passed to this script and we use the shell's built-in test command to find out if it's zero):



      if test $# -eq 0
      then
      startdir="$HOME"
      else
      startdir="$1"
      fi



    2. Iterate over files in your home directory. "$HOME"/* expands to all of the non-hidden files and directories at the top level of your home directory:



      for f in "$HOME"/*
      do



    3. Print the file name. I think you know echo:



           echo "$f"               # print the file name



    4. Call the shell built-in test command with the -d option. test returns true if the argument, "$f", is a directory. This is most often written as [ -d "$f" ] for brevity, but it really is a command. [Search for "test expr" in the sh man page]:



          if test -d "$f"         # is the file a directory? (-d)
      then



    5. This next statement is where we recur. We start a new copy of the currently running script and pass a the current "$f" directory name to it. The $0 expands to the filename of the current shell script. Rather than type some filename here, we use $0 so this script will work even if it's name is changed. For example, if the script was called rlist, then you could also write sh rlist "$f", but if the script was renamed, the script would no longer function correctly, because it would be calling a non-existent script, or the wrong script. [See "Special Parameters" in the sh man page]:



              sh "$0" "$f"         # yes call this script with the dir as arg



    6. Terminates the if statement and the for loop.



           fi
      done



    Counting the Files



    The script so far lists the files but does not count them. If you want to get a count of all the files and directories execute this:



    sh ./scriptname | wc -l


    wc -l is the "word count" command, and with the -l option counts only the lines. The above pipeline prints a number which is the number of files under your home directory.






    share|improve this answer















    There are many higher level commands that will almost do what you want to do, but this is a good demonstration of how to do the same thing in a shell script. This should work on any system that has /bin/sh. It's not dependent on any other commands.



    You can save this script as any filename, and then type sh ./whatever_you_named_it to execute it.



    I've split this into two sections, Listing the Files, and Counting the Files. Listing the files recursively is the most complicated, but once we have a list, it's easy to count them.



    Listing the Files



    This script recursively lists all of the files and directories under your home directory or a directory it receives as a parameter. With no parameters, it defaults to the home directory.



    #!/bin/sh

    if test $# -eq 0
    then
    startdir="$HOME"
    else
    startdir="$1"
    fi

    for f in "$start"/* # step through all files in the starting directory
    do
    echo "$f" # print the file name
    if test -d "$f" # is the file a directory? (-d)
    then
    sh "$0" "$f" # yes call this script with the dir as arg
    fi
    done


    Let's discuss each step:





    1. If no parameters were passed to the script, then use "$HOME" as the starting directory, otherwise use the first parameter. ($# contains the number of parameters passed to this script and we use the shell's built-in test command to find out if it's zero):



      if test $# -eq 0
      then
      startdir="$HOME"
      else
      startdir="$1"
      fi



    2. Iterate over files in your home directory. "$HOME"/* expands to all of the non-hidden files and directories at the top level of your home directory:



      for f in "$HOME"/*
      do



    3. Print the file name. I think you know echo:



           echo "$f"               # print the file name



    4. Call the shell built-in test command with the -d option. test returns true if the argument, "$f", is a directory. This is most often written as [ -d "$f" ] for brevity, but it really is a command. [Search for "test expr" in the sh man page]:



          if test -d "$f"         # is the file a directory? (-d)
      then



    5. This next statement is where we recur. We start a new copy of the currently running script and pass a the current "$f" directory name to it. The $0 expands to the filename of the current shell script. Rather than type some filename here, we use $0 so this script will work even if it's name is changed. For example, if the script was called rlist, then you could also write sh rlist "$f", but if the script was renamed, the script would no longer function correctly, because it would be calling a non-existent script, or the wrong script. [See "Special Parameters" in the sh man page]:



              sh "$0" "$f"         # yes call this script with the dir as arg



    6. Terminates the if statement and the for loop.



           fi
      done



    Counting the Files



    The script so far lists the files but does not count them. If you want to get a count of all the files and directories execute this:



    sh ./scriptname | wc -l


    wc -l is the "word count" command, and with the -l option counts only the lines. The above pipeline prints a number which is the number of files under your home directory.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Nov 10 '15 at 19:36

























    answered Nov 10 '15 at 2:30









    RobertLRobertL

    4,867624




    4,867624













    • you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

      – mikeserv
      Nov 10 '15 at 6:10













    • @mikeserv All true, but way beyond the level of understanding of the questioner.

      – RobertL
      Nov 10 '15 at 6:12











    • Let us continue this discussion in chat.

      – RobertL
      Nov 10 '15 at 6:17











    • @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

      – RobertL
      Nov 10 '15 at 19:39











    • @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

      – RobertL
      Nov 10 '15 at 19:41



















    • you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

      – mikeserv
      Nov 10 '15 at 6:10













    • @mikeserv All true, but way beyond the level of understanding of the questioner.

      – RobertL
      Nov 10 '15 at 6:12











    • Let us continue this discussion in chat.

      – RobertL
      Nov 10 '15 at 6:17











    • @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

      – RobertL
      Nov 10 '15 at 19:39











    • @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

      – RobertL
      Nov 10 '15 at 19:41

















    you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

    – mikeserv
    Nov 10 '15 at 6:10







    you should exec at least, but it would be better to use a function. as is you need a shell process - and a separate PID - per child directory. it also branches into infinite loops fairly easily with a few nasty symlink placements - which would make it a fork bomb.

    – mikeserv
    Nov 10 '15 at 6:10















    @mikeserv All true, but way beyond the level of understanding of the questioner.

    – RobertL
    Nov 10 '15 at 6:12





    @mikeserv All true, but way beyond the level of understanding of the questioner.

    – RobertL
    Nov 10 '15 at 6:12













    Let us continue this discussion in chat.

    – RobertL
    Nov 10 '15 at 6:17





    Let us continue this discussion in chat.

    – RobertL
    Nov 10 '15 at 6:17













    @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

    – RobertL
    Nov 10 '15 at 19:39





    @mikeserv Thanks! I can respond to that! Current version is tested. Thanks for bringing it down to my level! :--)

    – RobertL
    Nov 10 '15 at 19:39













    @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

    – RobertL
    Nov 10 '15 at 19:41





    @David-Prentice I just edited this to fix a serious problem. Please note the addition of the if statement at the top of the script. This is critical to keep the script from looping for ever.

    – RobertL
    Nov 10 '15 at 19:41













    3














    with find for not directory types in the current directory without recursing:



    find . ! -name . -prune ! -type d | grep -c /


    ...for only directories drop the second bang, or for all filetypes drop the -type test entirely.



    that's easy in this case because without recursion we only ever see one path delimiter per file and so there is no confusion about what and where to count. counting newlines when you should be counting files can lead to trouble - the two things are unrelated. so what to do otherwise?



    find .//. | grep -c '^.//.'


    ...will return an accurate count of child objects + this object rooted in the current directory.



    equally as valid, but with reversed logic because it quotes newlines internally and probably faster because it needs only to stat() each directory rather than every constituent file:



    ls -1qRA . | grep -Exc [^/]+


    if you drop the -R option to ls it will work without recursion just as well.



    it is possible, though, that the above could return a false count depending on multibyte characters in filenames and incompatible locale settings. putting LC_ALL=C in a POSIX-conformant ls's environment would protect against that, and for depth counts of a sizable tree, doing so can only help matters with regards to performance after all.






    share|improve this answer






























      3














      with find for not directory types in the current directory without recursing:



      find . ! -name . -prune ! -type d | grep -c /


      ...for only directories drop the second bang, or for all filetypes drop the -type test entirely.



      that's easy in this case because without recursion we only ever see one path delimiter per file and so there is no confusion about what and where to count. counting newlines when you should be counting files can lead to trouble - the two things are unrelated. so what to do otherwise?



      find .//. | grep -c '^.//.'


      ...will return an accurate count of child objects + this object rooted in the current directory.



      equally as valid, but with reversed logic because it quotes newlines internally and probably faster because it needs only to stat() each directory rather than every constituent file:



      ls -1qRA . | grep -Exc [^/]+


      if you drop the -R option to ls it will work without recursion just as well.



      it is possible, though, that the above could return a false count depending on multibyte characters in filenames and incompatible locale settings. putting LC_ALL=C in a POSIX-conformant ls's environment would protect against that, and for depth counts of a sizable tree, doing so can only help matters with regards to performance after all.






      share|improve this answer




























        3












        3








        3







        with find for not directory types in the current directory without recursing:



        find . ! -name . -prune ! -type d | grep -c /


        ...for only directories drop the second bang, or for all filetypes drop the -type test entirely.



        that's easy in this case because without recursion we only ever see one path delimiter per file and so there is no confusion about what and where to count. counting newlines when you should be counting files can lead to trouble - the two things are unrelated. so what to do otherwise?



        find .//. | grep -c '^.//.'


        ...will return an accurate count of child objects + this object rooted in the current directory.



        equally as valid, but with reversed logic because it quotes newlines internally and probably faster because it needs only to stat() each directory rather than every constituent file:



        ls -1qRA . | grep -Exc [^/]+


        if you drop the -R option to ls it will work without recursion just as well.



        it is possible, though, that the above could return a false count depending on multibyte characters in filenames and incompatible locale settings. putting LC_ALL=C in a POSIX-conformant ls's environment would protect against that, and for depth counts of a sizable tree, doing so can only help matters with regards to performance after all.






        share|improve this answer















        with find for not directory types in the current directory without recursing:



        find . ! -name . -prune ! -type d | grep -c /


        ...for only directories drop the second bang, or for all filetypes drop the -type test entirely.



        that's easy in this case because without recursion we only ever see one path delimiter per file and so there is no confusion about what and where to count. counting newlines when you should be counting files can lead to trouble - the two things are unrelated. so what to do otherwise?



        find .//. | grep -c '^.//.'


        ...will return an accurate count of child objects + this object rooted in the current directory.



        equally as valid, but with reversed logic because it quotes newlines internally and probably faster because it needs only to stat() each directory rather than every constituent file:



        ls -1qRA . | grep -Exc [^/]+


        if you drop the -R option to ls it will work without recursion just as well.



        it is possible, though, that the above could return a false count depending on multibyte characters in filenames and incompatible locale settings. putting LC_ALL=C in a POSIX-conformant ls's environment would protect against that, and for depth counts of a sizable tree, doing so can only help matters with regards to performance after all.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 10 '15 at 21:04

























        answered Nov 10 '15 at 5:17









        mikeservmikeserv

        45.8k668159




        45.8k668159























            0














            Use find:



            When you say non-recursively, did you mean that you only want a count of files/directories in /home, but not any subdirectories? If that is the case, you can restrict results to the top level with the maxdepth option.



            find /home -maxdepth 1 | wc -l


            Using for:



            i=0; for home in ~/*; do (( i++ )); done; echo $i


            Note the spaces between the double parentheses and the enclosed i++.






            share|improve this answer


























            • Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

              – terdon
              Nov 10 '15 at 11:50











            • @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

              – Nigel Tufnel
              Nov 10 '15 at 14:37











            • Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

              – terdon
              Nov 10 '15 at 14:43













            • are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

              – mikeserv
              Nov 10 '15 at 17:42
















            0














            Use find:



            When you say non-recursively, did you mean that you only want a count of files/directories in /home, but not any subdirectories? If that is the case, you can restrict results to the top level with the maxdepth option.



            find /home -maxdepth 1 | wc -l


            Using for:



            i=0; for home in ~/*; do (( i++ )); done; echo $i


            Note the spaces between the double parentheses and the enclosed i++.






            share|improve this answer


























            • Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

              – terdon
              Nov 10 '15 at 11:50











            • @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

              – Nigel Tufnel
              Nov 10 '15 at 14:37











            • Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

              – terdon
              Nov 10 '15 at 14:43













            • are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

              – mikeserv
              Nov 10 '15 at 17:42














            0












            0








            0







            Use find:



            When you say non-recursively, did you mean that you only want a count of files/directories in /home, but not any subdirectories? If that is the case, you can restrict results to the top level with the maxdepth option.



            find /home -maxdepth 1 | wc -l


            Using for:



            i=0; for home in ~/*; do (( i++ )); done; echo $i


            Note the spaces between the double parentheses and the enclosed i++.






            share|improve this answer















            Use find:



            When you say non-recursively, did you mean that you only want a count of files/directories in /home, but not any subdirectories? If that is the case, you can restrict results to the top level with the maxdepth option.



            find /home -maxdepth 1 | wc -l


            Using for:



            i=0; for home in ~/*; do (( i++ )); done; echo $i


            Note the spaces between the double parentheses and the enclosed i++.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 10 '15 at 15:38

























            answered Nov 10 '15 at 4:26









            Nigel TufnelNigel Tufnel

            1394




            1394













            • Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

              – terdon
              Nov 10 '15 at 11:50











            • @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

              – Nigel Tufnel
              Nov 10 '15 at 14:37











            • Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

              – terdon
              Nov 10 '15 at 14:43













            • are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

              – mikeserv
              Nov 10 '15 at 17:42



















            • Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

              – terdon
              Nov 10 '15 at 11:50











            • @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

              – Nigel Tufnel
              Nov 10 '15 at 14:37











            • Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

              – terdon
              Nov 10 '15 at 14:43













            • are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

              – mikeserv
              Nov 10 '15 at 17:42

















            Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

            – terdon
            Nov 10 '15 at 11:50





            Note that your find breaks for file/dir names containing newlines and the for breaks for just about everything, including simple spaces. In any case, this is recursive and the OP asked for a non-recursive solution.

            – terdon
            Nov 10 '15 at 11:50













            @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

            – Nigel Tufnel
            Nov 10 '15 at 14:37





            @terdon a bit harsh don't you think? The OP asked for a non-recursive solution and maxdepth would prevent recursion into subdirectories. The OP never mentioned filenames containing whitespace or newlines. Sure, that can be handled with quoting and -print0, respectively, but I simply wasn't giving him more than he asked for.

            – Nigel Tufnel
            Nov 10 '15 at 14:37













            Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

            – terdon
            Nov 10 '15 at 14:43







            Oh, good grief, sorry! I completely missed the -maxdepth option. Could you at least edit it into all of your suggestions? The for loop is still recursive. My main gripe though is i) this will break on strange filenames and ii) the for item in $(find) is very, very bad practice. At least use a shell glob for item in /home/* There's no point in using find if you specifically don't want recursion, that's just making it more complex and more fragile since it can't deal with whitespace correctly. The OP's original version deals with whitespace just fine.

            – terdon
            Nov 10 '15 at 14:43















            are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

            – mikeserv
            Nov 10 '15 at 17:42





            are you jim morrison? @terdon - the home thing is not recursive. oh. the (find ~) thing was in a previous version, yeah. the for loop is silly in any case: set -- ~/*; echo "$#" would behave identically and without the fuss. it doesnt handle dotfiles though - except . itself and only in the case of an empty directory. whats -maxdepth all about, anyway? ive never understood what it does, except that its supposed to go in a special arg position. i mean, does it offer anything that a simple -prune doesnt?

            – mikeserv
            Nov 10 '15 at 17:42


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Unix & Linux Stack Exchange!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f242002%2fhow-do-i-write-a-script-to-count-the-total-number-of-files-and-directories-in-m%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to make a Squid Proxy server?

            Is this a new Fibonacci Identity?

            19世紀