Remove pipes usage when reading the manifest file in collect_cc_coverage.sh

Replace reading the manifest using pipes with `read -r`. Using pipes is not an efficient way to read big files.

I created a small repo that only reads:
* a 200.000-lines file:
with pipes: 0m7.965s
with read:  0m2.835s
* a 2.000.000-lines file:
with pipes: 1m21.065s
with read:  0m29.215s

Closes #8331.

PiperOrigin-RevId: 248528367
diff --git a/tools/test/collect_cc_coverage.sh b/tools/test/collect_cc_coverage.sh
index 4ee1546..c55b8e9 100755
--- a/tools/test/collect_cc_coverage.sh
+++ b/tools/test/collect_cc_coverage.sh
@@ -84,56 +84,58 @@
 
   # Copy .gcno files next to their corresponding .gcda files in $COVERAGE_DIR
   # because gcov expects them to be in the same directory.
-  cat "${COVERAGE_MANIFEST}" | grep ".gcno$" | while read gcno_path; do
+  while read -r line; do
+    if [[ ${line: -4} == "gcno" ]]; then
+      gcno_path=${line}
+      local gcda="${COVERAGE_DIR}/$(dirname ${gcno_path})/$(basename ${gcno_path} .gcno).gcda"
+      # If the gcda file was not found we skip generating coverage from the gcno
+      # file.
+      if [[ -f "$gcda" ]]; then
+          # gcov expects both gcno and gcda files to be in the same directory.
+          # We overcome this by copying the gcno to $COVERAGE_DIR where the gcda
+          # files are expected to be.
+          if [ ! -f "${COVERAGE_DIR}/${gcno_path}" ]; then
+              mkdir -p "${COVERAGE_DIR}/$(dirname ${gcno_path})"
+              cp "$ROOT/${gcno_path}" "${COVERAGE_DIR}/${gcno_path}"
+          fi
+          # Invoke gcov to generate a code coverage report with the flags:
+          # -i              Output gcov file in an intermediate text format.
+          #                 The output is a single .gcov file per .gcda file.
+          #                 No source code is required.
+          # -o directory    The directory containing the .gcno and
+          #                 .gcda data files.
+          # "${gcda"}       The input file name. gcov is looking for data files
+          #                 named after the input filename without its extension.
+          # gcov produces files called <source file name>.gcov in the current
+          # directory. These contain the coverage information of the source file
+          # they correspond to. One .gcov file is produced for each source
+          # (or header) file containing code which was compiled to produce the
+          # .gcda files.
+          # Don't generate branch coverage (-b) because of a gcov issue that
+          # segfaults when both -i and -b are used (see
+          # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84879).
+          "${GCOV}" -i -o "$(dirname ${gcda})" "${gcda}" &> "$gcov_log"
 
-    local gcda="${COVERAGE_DIR}/$(dirname ${gcno_path})/$(basename ${gcno_path} .gcno).gcda"
-    # If the gcda file was not found we skip generating coverage from the gcno
-    # file.
-    if [[ -f "$gcda" ]]; then
-        # gcov expects both gcno and gcda files to be in the same directory.
-        # We overcome this by copying the gcno to $COVERAGE_DIR where the gcda
-        # files are expected to be.
-        if [ ! -f "${COVERAGE_DIR}/${gcno_path}" ]; then
-            mkdir -p "${COVERAGE_DIR}/$(dirname ${gcno_path})"
-            cp "$ROOT/${gcno_path}" "${COVERAGE_DIR}/${gcno_path}"
-        fi
-        # Invoke gcov to generate a code coverage report with the flags:
-        # -i              Output gcov file in an intermediate text format.
-        #                 The output is a single .gcov file per .gcda file.
-        #                 No source code is required.
-        # -o directory    The directory containing the .gcno and
-        #                 .gcda data files.
-        # "${gcda"}       The input file name. gcov is looking for data files
-        #                 named after the input filename without its extension.
-        # gcov produces files called <source file name>.gcov in the current
-        # directory. These contain the coverage information of the source file
-        # they correspond to. One .gcov file is produced for each source
-        # (or header) file containing code which was compiled to produce the
-        # .gcda files.
-        # Don't generate branch coverage (-b) because of a gcov issue that
-        # segfaults when both -i and -b are used (see
-        # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84879).
-        "${GCOV}" -i -o "$(dirname ${gcda})" "${gcda}" &> "$gcov_log"
-
-        # Go through all the files that were created by the gcov command above
-        # and append their content to the output .gcov file.
-        #
-        # For each source file gcov outputs to stdout something like this:
-        #
-        # File 'examples/cpp/hello-lib.cc'
-        # Lines executed:100.00% of 8
-        # Creating 'hello-lib.cc.gcov'
-        #
-        # We grep the names of the files that were created from that output.
-        cat "$gcov_log" | grep "Creating" | cut -d " " -f 2 | cut -d"'" -f2 | \
-            while read gcov_file; do
-          echo "Processing $gcov_file"
-          cat "$gcov_file" >> "$output_file"
-          # Remove the intermediate gcov file because it is not useful anymore.
-          rm -f "$gcov_file"
-        done
+          # Go through all the files that were created by the gcov command above
+          # and append their content to the output .gcov file.
+          #
+          # For each source file gcov outputs to stdout something like this:
+          #
+          # File 'examples/cpp/hello-lib.cc'
+          # Lines executed:100.00% of 8
+          # Creating 'hello-lib.cc.gcov'
+          #
+          # We grep the names of the files that were created from that output.
+          cat "$gcov_log" | grep "Creating" | cut -d " " -f 2 | cut -d"'" -f2 | \
+              while read gcov_file; do
+            echo "Processing $gcov_file"
+            cat "$gcov_file" >> "$output_file"
+            # Remove the intermediate gcov file because it is not useful anymore.
+            rm -f "$gcov_file"
+          done
+      fi
     fi
-  done
+  done < "${COVERAGE_MANIFEST}"
 }
 
 function main() {