Count line of code for a JavaScript projectIdeas on shortening this if-elsif chain with embedded if-elsifPerl parsing codeCounting words from standard input in SwiftParsing users from a list of commands for email notificationsMatching whitespace and non-whitespace characters with RegExRegular Expression to Remove CommentsMatching Fasta file header and section of sequence, printing each header only onceTrimming unicode whitespace, control characters, and line breaks with regexAverage spam confidence

Tips for attracting more math majors in a liberal arts college mathematics department

Multiple devices with one IPv6 to the Internet?

Term for anticipating counterarguments and rebutting them

why we need self-synchronization?

Does 'a window' close the possibility to be one and only one window in the room?

Proof that if covariance is zero then there is no linear relationship

What's the most profitable use for an elemental transmuter?

Noise reduction using multiple recordings of the same signal

What happens to a Bladesinger reincarnated as a Human?

Is it bizarre that a professor asks every student for a 3 inch by 5 inch photograph?

Is the ''yoi'' meaning ''ready'' when doing karate the same as the ''yoi'' which means nice/good?

How wavy is an array?

Antonym for “boilerplate” or “cookie-cutter”

How can an immortal member of the nobility be prevented from taking the throne?

How do I figure out how many hydrogens my compound actually has using a mass and NMR spectrum?

Command which removes data left side of ";" (semicolon) on each row

How much caffeine would there be if I reuse tea leaves in a second brewing?

Coworkers accusing me of "cheating" for working more efficiently

Why does Bane's stock exchange robbery actually work to bankrupt Bruce Wayne?

How could a sequence of random dates be generated, given year interval?

A partially ugly group with a casual secret

How TikZ uses $ for calculations of relative coordinates?

In Cura, can I make my top and bottom layer be all perimiters?

Novel in which space traders train a spearman army for a decaying medieval empire



Count line of code for a JavaScript project


Ideas on shortening this if-elsif chain with embedded if-elsifPerl parsing codeCounting words from standard input in SwiftParsing users from a list of commands for email notificationsMatching whitespace and non-whitespace characters with RegExRegular Expression to Remove CommentsMatching Fasta file header and section of sequence, printing each header only onceTrimming unicode whitespace, control characters, and line breaks with regexAverage spam confidence






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;









9














$begingroup$


Here is my bash script that I just wrote to count line of code for JavaScript project.



It will list number of:



  • Comment lines

  • Blank lines

  • All lines

Here is my script:



#!/bin/bash

fileExt="*.js"

allFiles=$(find ./ -name "$fileExt")

commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)

blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)

allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)

echo -e "nTotal comments line is: $commentLines.n
Total blank lines is: $blankLines.n
nTotal all lines is: $allLines."


Let me explain it a little bit:



First, we need to list all files that end with ".js" within the project:



allFiles=$(find ./ -name "$fileExt")


Second, we count all comment lines:



commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)


There are 2 types of comment lines in JavaScript:




  1. Line start with only space and // or only //



    Example:



    //this is a comment line


    // this is a comment line
    // this also is a comment line



    All above are comment lines, and we got 3 lines total here. But the following is not comment lines:



    function foo(params 1) // return void




    The line contains // return void is not considered as a comment, so we do not need to count it.



    And for the kind of comment line. I using the regex with perl to print all comment lines that match with regex:



    /(^s+//s*w+)/sg



  2. Multi-line comment (JSDOC):



    Example:



    /**
    * return something
    * @param object obj
    * return void
    */


    So we need to count all number of lines that start from the line with /** and end with */, we have 5 lines here.



    I use this regex to match:



    perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles


    So the total number of comment lines is the sum of two types comment lines above.



Third



We need to count blank lines.



I use the following command to match:



grep '^[[:space:]]*//' -r --include $fileExt | wc -l


Finally



We need to count all lines:



echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2


I wonder if my solution is good enough or not.










share|improve this question












$endgroup$





















    9














    $begingroup$


    Here is my bash script that I just wrote to count line of code for JavaScript project.



    It will list number of:



    • Comment lines

    • Blank lines

    • All lines

    Here is my script:



    #!/bin/bash

    fileExt="*.js"

    allFiles=$(find ./ -name "$fileExt")

    commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
    perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)

    blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)

    allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)

    echo -e "nTotal comments line is: $commentLines.n
    Total blank lines is: $blankLines.n
    nTotal all lines is: $allLines."


    Let me explain it a little bit:



    First, we need to list all files that end with ".js" within the project:



    allFiles=$(find ./ -name "$fileExt")


    Second, we count all comment lines:



    commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
    perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)


    There are 2 types of comment lines in JavaScript:




    1. Line start with only space and // or only //



      Example:



      //this is a comment line


      // this is a comment line
      // this also is a comment line



      All above are comment lines, and we got 3 lines total here. But the following is not comment lines:



      function foo(params 1) // return void




      The line contains // return void is not considered as a comment, so we do not need to count it.



      And for the kind of comment line. I using the regex with perl to print all comment lines that match with regex:



      /(^s+//s*w+)/sg



    2. Multi-line comment (JSDOC):



      Example:



      /**
      * return something
      * @param object obj
      * return void
      */


      So we need to count all number of lines that start from the line with /** and end with */, we have 5 lines here.



      I use this regex to match:



      perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles


      So the total number of comment lines is the sum of two types comment lines above.



    Third



    We need to count blank lines.



    I use the following command to match:



    grep '^[[:space:]]*//' -r --include $fileExt | wc -l


    Finally



    We need to count all lines:



    echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2


    I wonder if my solution is good enough or not.










    share|improve this question












    $endgroup$

















      9












      9








      9





      $begingroup$


      Here is my bash script that I just wrote to count line of code for JavaScript project.



      It will list number of:



      • Comment lines

      • Blank lines

      • All lines

      Here is my script:



      #!/bin/bash

      fileExt="*.js"

      allFiles=$(find ./ -name "$fileExt")

      commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
      perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)

      blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)

      allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)

      echo -e "nTotal comments line is: $commentLines.n
      Total blank lines is: $blankLines.n
      nTotal all lines is: $allLines."


      Let me explain it a little bit:



      First, we need to list all files that end with ".js" within the project:



      allFiles=$(find ./ -name "$fileExt")


      Second, we count all comment lines:



      commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
      perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)


      There are 2 types of comment lines in JavaScript:




      1. Line start with only space and // or only //



        Example:



        //this is a comment line


        // this is a comment line
        // this also is a comment line



        All above are comment lines, and we got 3 lines total here. But the following is not comment lines:



        function foo(params 1) // return void




        The line contains // return void is not considered as a comment, so we do not need to count it.



        And for the kind of comment line. I using the regex with perl to print all comment lines that match with regex:



        /(^s+//s*w+)/sg



      2. Multi-line comment (JSDOC):



        Example:



        /**
        * return something
        * @param object obj
        * return void
        */


        So we need to count all number of lines that start from the line with /** and end with */, we have 5 lines here.



        I use this regex to match:



        perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles


        So the total number of comment lines is the sum of two types comment lines above.



      Third



      We need to count blank lines.



      I use the following command to match:



      grep '^[[:space:]]*//' -r --include $fileExt | wc -l


      Finally



      We need to count all lines:



      echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2


      I wonder if my solution is good enough or not.










      share|improve this question












      $endgroup$




      Here is my bash script that I just wrote to count line of code for JavaScript project.



      It will list number of:



      • Comment lines

      • Blank lines

      • All lines

      Here is my script:



      #!/bin/bash

      fileExt="*.js"

      allFiles=$(find ./ -name "$fileExt")

      commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
      perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)

      blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)

      allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)

      echo -e "nTotal comments line is: $commentLines.n
      Total blank lines is: $blankLines.n
      nTotal all lines is: $allLines."


      Let me explain it a little bit:



      First, we need to list all files that end with ".js" within the project:



      allFiles=$(find ./ -name "$fileExt")


      Second, we count all comment lines:



      commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
      perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)


      There are 2 types of comment lines in JavaScript:




      1. Line start with only space and // or only //



        Example:



        //this is a comment line


        // this is a comment line
        // this also is a comment line



        All above are comment lines, and we got 3 lines total here. But the following is not comment lines:



        function foo(params 1) // return void




        The line contains // return void is not considered as a comment, so we do not need to count it.



        And for the kind of comment line. I using the regex with perl to print all comment lines that match with regex:



        /(^s+//s*w+)/sg



      2. Multi-line comment (JSDOC):



        Example:



        /**
        * return something
        * @param object obj
        * return void
        */


        So we need to count all number of lines that start from the line with /** and end with */, we have 5 lines here.



        I use this regex to match:



        perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles


        So the total number of comment lines is the sum of two types comment lines above.



      Third



      We need to count blank lines.



      I use the following command to match:



      grep '^[[:space:]]*//' -r --include $fileExt | wc -l


      Finally



      We need to count all lines:



      echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2


      I wonder if my solution is good enough or not.







      regex bash shell perl sh






      share|improve this question
















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jun 2 at 2:20









      Jamal

      32.1k12 gold badges123 silver badges231 bronze badges




      32.1k12 gold badges123 silver badges231 bronze badges










      asked May 31 at 4:11









      chau giangchau giang

      1015 bronze badges




      1015 bronze badges























          2 Answers
          2






          active

          oldest

          votes


















          7
















          $begingroup$


          fileExt="*.js"
          allFiles=$(find ./ -name $fileExt)



          This is a bug. The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:



          $ touch a.js b.js
          $ fileExt="*.js"
          $ find ./ -name $fileExt
          find: paths must precede expression: `b.js'
          find: possible unquoted pattern after predicate `-name'?


          You need to quote the variable. Better yet, use the globstar option to populate an array and eliminate find altogether:



          fileExt="js"
          shopt -s globstar
          declare -a allFiles=( **/*.$fileExt )
          grep … "$allFiles[@]" # to use the array


          This regex does not match blank lines:




          grep '^[[:space:]]*//' 



          Just /* is enough to start a multi-line comment in JavaScript (not /**).



          The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:



          #!/bin/bash
          shopt -s globstar
          exec perl -nle '
          BEGIN
          @ARGV=grep -f, @ARGV or die "no matching filesn";
          $comment = $blank = 0;

          if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
          elsif ( m ^s*$ x ) $blank++
          END print "$comment comment lines; $blank blank lines; $. total lines"
          ' **/*.js


          At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:



          #!/usr/bin/perl -wnl
          BEGIN
          use strict;
          use File::Find;
          my $ext="js";
          my @dirs=( @ARGV ? @ARGV : '.' );
          @ARGV=();
          find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
          our ($comment, $blank) = (0, 0);


          if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
          elsif ( m ^s*$ x ) $blank++

          END
          print "$comment comment lines; $blank blank lines; $. total lines";






          share|improve this answer












          $endgroup$










          • 1




            $begingroup$
            Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
            $endgroup$
            – chau giang
            May 31 at 7:58










          • $begingroup$
            I understand this: grep '^[[:space:]]*//', this is my mistake!
            $endgroup$
            – chau giang
            May 31 at 7:59







          • 2




            $begingroup$
            Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
            $endgroup$
            – Oh My Goodness
            May 31 at 14:07











          • $begingroup$
            The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
            $endgroup$
            – chau giang
            Jun 3 at 4:36



















          5
















          $begingroup$

          General



          Run shellcheck on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e (prefer printf instead) and a dodgy use of $(( where $( ( would be safer.



          I recommend setting -u and -e shell options to help you catch more errors.



          Flexibility



          Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:



          dirs=("$@:-.")


          Finding files



          allFiles will include directories and other non-regular files, if they happen to end in .js. We need to add a file type predicate:



          allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)


          Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:



          allFiles=()
          while IFS= read -r -d ''; do
          allFiles+=("$REPLY")
          done < <(find ./ -name "$fileExt" -type f -print0)


          It may almost be simpler to set globstar shell option and then remove non-regular files from the glob result.



          Counting comment lines



          I didn't follow your Perl code, but I have an alternative approach using sed:



          • convert all lines from initial /** to final */ to begin with // instead,

          • then keep only the lines beginning with optional whitespace then //:

          sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/' 
          -e '|^[[:blank:]]*//|!d'


          (Actually, that's a lot less pretty than I'd hoped!)



          Blank lines



          Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$' instead, to match lines that contain only (optional) whitespace.



          All lines



          Again, over-complicated: just cat the files together and then use wc -l.



          Printing



          I find it easier to visualise output formatting if we simply use a here-document:



          cat <<EOF
          Total comments lines is: $commentLines.
          Total blank lines is: $blankLines.
          Total all lines is: $allLines.
          EOF
          exit



          Modified code



          #!/bin/bash
          set -eu

          fileExt='*.js'
          dirs=("$@:-/usr/lib/nodejs/lodash")

          allFiles=()
          while IFS= read -r -d ''; do
          allFiles+=("$REPLY")
          done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)

          commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
          -e '|^[[:blank:]]*//|!d'
          "$allFiles[@]" | wc -l)
          blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
          allLines=$(cat "$allFiles[@]" | wc -l)

          cat <<EOF
          Total comment lines is: $commentLines.
          Total blank lines is: $blankLines.
          Total all lines is: $allLines.
          EOF


          Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).




          Single-pass version using awk



          A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk program. Note that with no arrays, we can make this a POSIX shell program:



          #!/bin/sh
          set -eu

          fileExt='*.js'

          find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
          awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;

          ++all
          if ($0 ~ "/\*") incomment = 1
          if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
          else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")

          END print "Total comment lines is:", comment
          print "Total blank lines is:", blank
          print "Total all lines is:", all '





          share|improve this answer












          $endgroup$
















            Your Answer






            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            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/4.0/"u003ecc by-sa 4.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%2fcodereview.stackexchange.com%2fquestions%2f221378%2fcount-line-of-code-for-a-javascript-project%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown


























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            7
















            $begingroup$


            fileExt="*.js"
            allFiles=$(find ./ -name $fileExt)



            This is a bug. The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:



            $ touch a.js b.js
            $ fileExt="*.js"
            $ find ./ -name $fileExt
            find: paths must precede expression: `b.js'
            find: possible unquoted pattern after predicate `-name'?


            You need to quote the variable. Better yet, use the globstar option to populate an array and eliminate find altogether:



            fileExt="js"
            shopt -s globstar
            declare -a allFiles=( **/*.$fileExt )
            grep … "$allFiles[@]" # to use the array


            This regex does not match blank lines:




            grep '^[[:space:]]*//' 



            Just /* is enough to start a multi-line comment in JavaScript (not /**).



            The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:



            #!/bin/bash
            shopt -s globstar
            exec perl -nle '
            BEGIN
            @ARGV=grep -f, @ARGV or die "no matching filesn";
            $comment = $blank = 0;

            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++
            END print "$comment comment lines; $blank blank lines; $. total lines"
            ' **/*.js


            At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:



            #!/usr/bin/perl -wnl
            BEGIN
            use strict;
            use File::Find;
            my $ext="js";
            my @dirs=( @ARGV ? @ARGV : '.' );
            @ARGV=();
            find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
            our ($comment, $blank) = (0, 0);


            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++

            END
            print "$comment comment lines; $blank blank lines; $. total lines";






            share|improve this answer












            $endgroup$










            • 1




              $begingroup$
              Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
              $endgroup$
              – chau giang
              May 31 at 7:58










            • $begingroup$
              I understand this: grep '^[[:space:]]*//', this is my mistake!
              $endgroup$
              – chau giang
              May 31 at 7:59







            • 2




              $begingroup$
              Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
              $endgroup$
              – Oh My Goodness
              May 31 at 14:07











            • $begingroup$
              The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
              $endgroup$
              – chau giang
              Jun 3 at 4:36
















            7
















            $begingroup$


            fileExt="*.js"
            allFiles=$(find ./ -name $fileExt)



            This is a bug. The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:



            $ touch a.js b.js
            $ fileExt="*.js"
            $ find ./ -name $fileExt
            find: paths must precede expression: `b.js'
            find: possible unquoted pattern after predicate `-name'?


            You need to quote the variable. Better yet, use the globstar option to populate an array and eliminate find altogether:



            fileExt="js"
            shopt -s globstar
            declare -a allFiles=( **/*.$fileExt )
            grep … "$allFiles[@]" # to use the array


            This regex does not match blank lines:




            grep '^[[:space:]]*//' 



            Just /* is enough to start a multi-line comment in JavaScript (not /**).



            The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:



            #!/bin/bash
            shopt -s globstar
            exec perl -nle '
            BEGIN
            @ARGV=grep -f, @ARGV or die "no matching filesn";
            $comment = $blank = 0;

            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++
            END print "$comment comment lines; $blank blank lines; $. total lines"
            ' **/*.js


            At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:



            #!/usr/bin/perl -wnl
            BEGIN
            use strict;
            use File::Find;
            my $ext="js";
            my @dirs=( @ARGV ? @ARGV : '.' );
            @ARGV=();
            find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
            our ($comment, $blank) = (0, 0);


            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++

            END
            print "$comment comment lines; $blank blank lines; $. total lines";






            share|improve this answer












            $endgroup$










            • 1




              $begingroup$
              Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
              $endgroup$
              – chau giang
              May 31 at 7:58










            • $begingroup$
              I understand this: grep '^[[:space:]]*//', this is my mistake!
              $endgroup$
              – chau giang
              May 31 at 7:59







            • 2




              $begingroup$
              Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
              $endgroup$
              – Oh My Goodness
              May 31 at 14:07











            • $begingroup$
              The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
              $endgroup$
              – chau giang
              Jun 3 at 4:36














            7














            7










            7







            $begingroup$


            fileExt="*.js"
            allFiles=$(find ./ -name $fileExt)



            This is a bug. The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:



            $ touch a.js b.js
            $ fileExt="*.js"
            $ find ./ -name $fileExt
            find: paths must precede expression: `b.js'
            find: possible unquoted pattern after predicate `-name'?


            You need to quote the variable. Better yet, use the globstar option to populate an array and eliminate find altogether:



            fileExt="js"
            shopt -s globstar
            declare -a allFiles=( **/*.$fileExt )
            grep … "$allFiles[@]" # to use the array


            This regex does not match blank lines:




            grep '^[[:space:]]*//' 



            Just /* is enough to start a multi-line comment in JavaScript (not /**).



            The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:



            #!/bin/bash
            shopt -s globstar
            exec perl -nle '
            BEGIN
            @ARGV=grep -f, @ARGV or die "no matching filesn";
            $comment = $blank = 0;

            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++
            END print "$comment comment lines; $blank blank lines; $. total lines"
            ' **/*.js


            At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:



            #!/usr/bin/perl -wnl
            BEGIN
            use strict;
            use File::Find;
            my $ext="js";
            my @dirs=( @ARGV ? @ARGV : '.' );
            @ARGV=();
            find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
            our ($comment, $blank) = (0, 0);


            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++

            END
            print "$comment comment lines; $blank blank lines; $. total lines";






            share|improve this answer












            $endgroup$




            fileExt="*.js"
            allFiles=$(find ./ -name $fileExt)



            This is a bug. The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:



            $ touch a.js b.js
            $ fileExt="*.js"
            $ find ./ -name $fileExt
            find: paths must precede expression: `b.js'
            find: possible unquoted pattern after predicate `-name'?


            You need to quote the variable. Better yet, use the globstar option to populate an array and eliminate find altogether:



            fileExt="js"
            shopt -s globstar
            declare -a allFiles=( **/*.$fileExt )
            grep … "$allFiles[@]" # to use the array


            This regex does not match blank lines:




            grep '^[[:space:]]*//' 



            Just /* is enough to start a multi-line comment in JavaScript (not /**).



            The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:



            #!/bin/bash
            shopt -s globstar
            exec perl -nle '
            BEGIN
            @ARGV=grep -f, @ARGV or die "no matching filesn";
            $comment = $blank = 0;

            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++
            END print "$comment comment lines; $blank blank lines; $. total lines"
            ' **/*.js


            At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:



            #!/usr/bin/perl -wnl
            BEGIN
            use strict;
            use File::Find;
            my $ext="js";
            my @dirs=( @ARGV ? @ARGV : '.' );
            @ARGV=();
            find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
            our ($comment, $blank) = (0, 0);


            if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
            elsif ( m ^s*$ x ) $blank++

            END
            print "$comment comment lines; $blank blank lines; $. total lines";







            share|improve this answer















            share|improve this answer




            share|improve this answer








            edited May 31 at 18:56









            Timo

            4021 gold badge4 silver badges8 bronze badges




            4021 gold badge4 silver badges8 bronze badges










            answered May 31 at 5:52









            Oh My GoodnessOh My Goodness

            3,6801 gold badge4 silver badges22 bronze badges




            3,6801 gold badge4 silver badges22 bronze badges










            • 1




              $begingroup$
              Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
              $endgroup$
              – chau giang
              May 31 at 7:58










            • $begingroup$
              I understand this: grep '^[[:space:]]*//', this is my mistake!
              $endgroup$
              – chau giang
              May 31 at 7:59







            • 2




              $begingroup$
              Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
              $endgroup$
              – Oh My Goodness
              May 31 at 14:07











            • $begingroup$
              The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
              $endgroup$
              – chau giang
              Jun 3 at 4:36













            • 1




              $begingroup$
              Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
              $endgroup$
              – chau giang
              May 31 at 7:58










            • $begingroup$
              I understand this: grep '^[[:space:]]*//', this is my mistake!
              $endgroup$
              – chau giang
              May 31 at 7:59







            • 2




              $begingroup$
              Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
              $endgroup$
              – Oh My Goodness
              May 31 at 14:07











            • $begingroup$
              The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
              $endgroup$
              – chau giang
              Jun 3 at 4:36








            1




            1




            $begingroup$
            Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
            $endgroup$
            – chau giang
            May 31 at 7:58




            $begingroup$
            Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
            $endgroup$
            – chau giang
            May 31 at 7:58












            $begingroup$
            I understand this: grep '^[[:space:]]*//', this is my mistake!
            $endgroup$
            – chau giang
            May 31 at 7:59





            $begingroup$
            I understand this: grep '^[[:space:]]*//', this is my mistake!
            $endgroup$
            – chau giang
            May 31 at 7:59





            2




            2




            $begingroup$
            Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
            $endgroup$
            – Oh My Goodness
            May 31 at 14:07





            $begingroup$
            Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
            $endgroup$
            – Oh My Goodness
            May 31 at 14:07













            $begingroup$
            The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
            $endgroup$
            – chau giang
            Jun 3 at 4:36





            $begingroup$
            The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
            $endgroup$
            – chau giang
            Jun 3 at 4:36














            5
















            $begingroup$

            General



            Run shellcheck on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e (prefer printf instead) and a dodgy use of $(( where $( ( would be safer.



            I recommend setting -u and -e shell options to help you catch more errors.



            Flexibility



            Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:



            dirs=("$@:-.")


            Finding files



            allFiles will include directories and other non-regular files, if they happen to end in .js. We need to add a file type predicate:



            allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)


            Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:



            allFiles=()
            while IFS= read -r -d ''; do
            allFiles+=("$REPLY")
            done < <(find ./ -name "$fileExt" -type f -print0)


            It may almost be simpler to set globstar shell option and then remove non-regular files from the glob result.



            Counting comment lines



            I didn't follow your Perl code, but I have an alternative approach using sed:



            • convert all lines from initial /** to final */ to begin with // instead,

            • then keep only the lines beginning with optional whitespace then //:

            sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/' 
            -e '|^[[:blank:]]*//|!d'


            (Actually, that's a lot less pretty than I'd hoped!)



            Blank lines



            Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$' instead, to match lines that contain only (optional) whitespace.



            All lines



            Again, over-complicated: just cat the files together and then use wc -l.



            Printing



            I find it easier to visualise output formatting if we simply use a here-document:



            cat <<EOF
            Total comments lines is: $commentLines.
            Total blank lines is: $blankLines.
            Total all lines is: $allLines.
            EOF
            exit



            Modified code



            #!/bin/bash
            set -eu

            fileExt='*.js'
            dirs=("$@:-/usr/lib/nodejs/lodash")

            allFiles=()
            while IFS= read -r -d ''; do
            allFiles+=("$REPLY")
            done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)

            commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
            -e '|^[[:blank:]]*//|!d'
            "$allFiles[@]" | wc -l)
            blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
            allLines=$(cat "$allFiles[@]" | wc -l)

            cat <<EOF
            Total comment lines is: $commentLines.
            Total blank lines is: $blankLines.
            Total all lines is: $allLines.
            EOF


            Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).




            Single-pass version using awk



            A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk program. Note that with no arrays, we can make this a POSIX shell program:



            #!/bin/sh
            set -eu

            fileExt='*.js'

            find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
            awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;

            ++all
            if ($0 ~ "/\*") incomment = 1
            if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
            else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")

            END print "Total comment lines is:", comment
            print "Total blank lines is:", blank
            print "Total all lines is:", all '





            share|improve this answer












            $endgroup$



















              5
















              $begingroup$

              General



              Run shellcheck on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e (prefer printf instead) and a dodgy use of $(( where $( ( would be safer.



              I recommend setting -u and -e shell options to help you catch more errors.



              Flexibility



              Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:



              dirs=("$@:-.")


              Finding files



              allFiles will include directories and other non-regular files, if they happen to end in .js. We need to add a file type predicate:



              allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)


              Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:



              allFiles=()
              while IFS= read -r -d ''; do
              allFiles+=("$REPLY")
              done < <(find ./ -name "$fileExt" -type f -print0)


              It may almost be simpler to set globstar shell option and then remove non-regular files from the glob result.



              Counting comment lines



              I didn't follow your Perl code, but I have an alternative approach using sed:



              • convert all lines from initial /** to final */ to begin with // instead,

              • then keep only the lines beginning with optional whitespace then //:

              sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/' 
              -e '|^[[:blank:]]*//|!d'


              (Actually, that's a lot less pretty than I'd hoped!)



              Blank lines



              Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$' instead, to match lines that contain only (optional) whitespace.



              All lines



              Again, over-complicated: just cat the files together and then use wc -l.



              Printing



              I find it easier to visualise output formatting if we simply use a here-document:



              cat <<EOF
              Total comments lines is: $commentLines.
              Total blank lines is: $blankLines.
              Total all lines is: $allLines.
              EOF
              exit



              Modified code



              #!/bin/bash
              set -eu

              fileExt='*.js'
              dirs=("$@:-/usr/lib/nodejs/lodash")

              allFiles=()
              while IFS= read -r -d ''; do
              allFiles+=("$REPLY")
              done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)

              commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
              -e '|^[[:blank:]]*//|!d'
              "$allFiles[@]" | wc -l)
              blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
              allLines=$(cat "$allFiles[@]" | wc -l)

              cat <<EOF
              Total comment lines is: $commentLines.
              Total blank lines is: $blankLines.
              Total all lines is: $allLines.
              EOF


              Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).




              Single-pass version using awk



              A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk program. Note that with no arrays, we can make this a POSIX shell program:



              #!/bin/sh
              set -eu

              fileExt='*.js'

              find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
              awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;

              ++all
              if ($0 ~ "/\*") incomment = 1
              if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
              else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")

              END print "Total comment lines is:", comment
              print "Total blank lines is:", blank
              print "Total all lines is:", all '





              share|improve this answer












              $endgroup$

















                5














                5










                5







                $begingroup$

                General



                Run shellcheck on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e (prefer printf instead) and a dodgy use of $(( where $( ( would be safer.



                I recommend setting -u and -e shell options to help you catch more errors.



                Flexibility



                Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:



                dirs=("$@:-.")


                Finding files



                allFiles will include directories and other non-regular files, if they happen to end in .js. We need to add a file type predicate:



                allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)


                Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:



                allFiles=()
                while IFS= read -r -d ''; do
                allFiles+=("$REPLY")
                done < <(find ./ -name "$fileExt" -type f -print0)


                It may almost be simpler to set globstar shell option and then remove non-regular files from the glob result.



                Counting comment lines



                I didn't follow your Perl code, but I have an alternative approach using sed:



                • convert all lines from initial /** to final */ to begin with // instead,

                • then keep only the lines beginning with optional whitespace then //:

                sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/' 
                -e '|^[[:blank:]]*//|!d'


                (Actually, that's a lot less pretty than I'd hoped!)



                Blank lines



                Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$' instead, to match lines that contain only (optional) whitespace.



                All lines



                Again, over-complicated: just cat the files together and then use wc -l.



                Printing



                I find it easier to visualise output formatting if we simply use a here-document:



                cat <<EOF
                Total comments lines is: $commentLines.
                Total blank lines is: $blankLines.
                Total all lines is: $allLines.
                EOF
                exit



                Modified code



                #!/bin/bash
                set -eu

                fileExt='*.js'
                dirs=("$@:-/usr/lib/nodejs/lodash")

                allFiles=()
                while IFS= read -r -d ''; do
                allFiles+=("$REPLY")
                done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)

                commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
                -e '|^[[:blank:]]*//|!d'
                "$allFiles[@]" | wc -l)
                blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
                allLines=$(cat "$allFiles[@]" | wc -l)

                cat <<EOF
                Total comment lines is: $commentLines.
                Total blank lines is: $blankLines.
                Total all lines is: $allLines.
                EOF


                Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).




                Single-pass version using awk



                A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk program. Note that with no arrays, we can make this a POSIX shell program:



                #!/bin/sh
                set -eu

                fileExt='*.js'

                find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
                awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;

                ++all
                if ($0 ~ "/\*") incomment = 1
                if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
                else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")

                END print "Total comment lines is:", comment
                print "Total blank lines is:", blank
                print "Total all lines is:", all '





                share|improve this answer












                $endgroup$



                General



                Run shellcheck on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e (prefer printf instead) and a dodgy use of $(( where $( ( would be safer.



                I recommend setting -u and -e shell options to help you catch more errors.



                Flexibility



                Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:



                dirs=("$@:-.")


                Finding files



                allFiles will include directories and other non-regular files, if they happen to end in .js. We need to add a file type predicate:



                allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)


                Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:



                allFiles=()
                while IFS= read -r -d ''; do
                allFiles+=("$REPLY")
                done < <(find ./ -name "$fileExt" -type f -print0)


                It may almost be simpler to set globstar shell option and then remove non-regular files from the glob result.



                Counting comment lines



                I didn't follow your Perl code, but I have an alternative approach using sed:



                • convert all lines from initial /** to final */ to begin with // instead,

                • then keep only the lines beginning with optional whitespace then //:

                sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/' 
                -e '|^[[:blank:]]*//|!d'


                (Actually, that's a lot less pretty than I'd hoped!)



                Blank lines



                Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$' instead, to match lines that contain only (optional) whitespace.



                All lines



                Again, over-complicated: just cat the files together and then use wc -l.



                Printing



                I find it easier to visualise output formatting if we simply use a here-document:



                cat <<EOF
                Total comments lines is: $commentLines.
                Total blank lines is: $blankLines.
                Total all lines is: $allLines.
                EOF
                exit



                Modified code



                #!/bin/bash
                set -eu

                fileExt='*.js'
                dirs=("$@:-/usr/lib/nodejs/lodash")

                allFiles=()
                while IFS= read -r -d ''; do
                allFiles+=("$REPLY")
                done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)

                commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
                -e '|^[[:blank:]]*//|!d'
                "$allFiles[@]" | wc -l)
                blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
                allLines=$(cat "$allFiles[@]" | wc -l)

                cat <<EOF
                Total comment lines is: $commentLines.
                Total blank lines is: $blankLines.
                Total all lines is: $allLines.
                EOF


                Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).




                Single-pass version using awk



                A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk program. Note that with no arrays, we can make this a POSIX shell program:



                #!/bin/sh
                set -eu

                fileExt='*.js'

                find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
                awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;

                ++all
                if ($0 ~ "/\*") incomment = 1
                if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
                else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")

                END print "Total comment lines is:", comment
                print "Total blank lines is:", blank
                print "Total all lines is:", all '






                share|improve this answer















                share|improve this answer




                share|improve this answer








                edited Jun 3 at 10:19

























                answered May 31 at 13:18









                Toby SpeightToby Speight

                32.9k7 gold badges46 silver badges142 bronze badges




                32.9k7 gold badges46 silver badges142 bronze badges































                    draft saved

                    draft discarded















































                    Thanks for contributing an answer to Code Review 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.

                    Use MathJax to format equations. MathJax reference.


                    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%2fcodereview.stackexchange.com%2fquestions%2f221378%2fcount-line-of-code-for-a-javascript-project%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

                    Tamil (spriik) Luke uk diar | Nawigatjuun

                    Align equal signs while including text over equalitiesAMS align: left aligned text/math plus multicolumn alignmentMultiple alignmentsAligning equations in multiple placesNumbering and aligning an equation with multiple columnsHow to align one equation with another multline equationUsing \ in environments inside the begintabularxNumber equations and preserving alignment of equal signsHow can I align equations to the left and to the right?Double equation alignment problem within align enviromentAligned within align: Why are they right-aligned?

                    Where does the image of a data connector as a sharp metal spike originate from?Where does the concept of infected people turning into zombies only after death originate from?Where does the motif of a reanimated human head originate?Where did the notion that Dragons could speak originate?Where does the archetypal image of the 'Grey' alien come from?Where did the suffix '-Man' originate?Where does the notion of being injured or killed by an illusion originate?Where did the term “sophont” originate?Where does the trope of magic spells being driven by advanced technology originate from?Where did the term “the living impaired” originate?