1

I apologize if this is a trivial question. I am learning how to use linux bash and this little task is giving me a headache...

So I need to write a script, let's call it count.sh. I want that: for each file in the working directory, prints the filename, the number of lines, and the number of words to the console:

test.txt 100 1023

someOtherfiles 10 233

So far, I know that the following gives me all the files names in the directory. And thanks for all who helped me, I get this working version:

for f in *; do
echo -n "$f"
cat "$f" | wc -wl
done

I would really appreciate your help! Thanks ahead!

P.s. If you know great resources (links for tutorials) for learning about script and you are willing to share it with me. I think I really need to know these basics. Thanks again!

Victoria J.
  • 323
  • 2
  • 12

2 Answers2

0

If you must have the file name as the first field in your output, try this:

for f in *; do
  if [ -f "$f" ]; then
    echo -n "$f"
    cat "$f" | wc -wl
  fi
done
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Oh! Thanks a lot! Now I start to connecting all the dots now. Just now I realized that I need to use cat, instead of just trying to interchange positions! @R Sahu – Victoria J. Apr 16 '14 at 03:27
  • @R Sahu One more little thing. Do you know how can I filter out directories (folders) so that I only wc text files? – Victoria J. Apr 16 '14 at 03:31
  • Works, but it's generally better to use `[[ ... ]]` rather than `[ ... ]` in `bash` (more robust, more features). Also, the `cat` is not needed: `wc -wl "$f"` will do (or, to be extra safe, `wc -wl -- "$f"`). Consider using command substitution to combine output from both commands. – mklement0 Apr 16 '14 at 03:40
  • @mklement0, `wc -wl "$f"` prints the name of the file after the number of words and number of lines, at least on my machine. Using `cat` was a method to avoid that. – R Sahu Apr 16 '14 at 03:42
  • @RSahu: Excellent point, thanks for clarifying. So what you should do to avoid the `cat` (and subshells that come with using a pipe) is: `wc -wl < "$f"`. – mklement0 Apr 16 '14 at 03:44
  • @mklement0 Are you implying that `wc -wl < "$f"` is better than `cat "$f" | wc -wl`? If you are, I would love to read up on the subject, if you can point me to a relevant place. – R Sahu Apr 16 '14 at 03:49
  • @RSahu: Yes, it is better for (a) concision (easier to type, easier to comprehend - assuming you're familiar with the `< file` idiom) and (b) efficiency (resource usage, execution speed). (b) will hardly matter in this simple case, but avoiding unnecessary external processes and subshells is generally advisable. In the case at hand, your version of the command creates _3 extra processes_: 2 subshells - 1 for each segment of the pipeline, and 1 for `cat`. There's plenty of info [here](http://stackoverflow.com/q/11710552/45375); let me know if you need more. – mklement0 Apr 16 '14 at 03:58
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/50744/discussion-between-r-sahu-and-mklement0) – R Sahu Apr 16 '14 at 04:12
  • Why ``cat`` when you can just ``wc -wl "$f"``. Also please prefer ``[[ ]]`` instead of ``[ ]``. – Aleks-Daniel Jakimenko-A. Jul 02 '14 at 06:06
0
for f in *; do
  if [[ -f $f ]]; then
    echo "$f $(wc -wl < "$f")"
  fi
done
  • [[ -f $f ]] processes only files (excludes subdirectories) and also handles the case where the directory is empty (in which case * is (by default) left unexpanded, i.e. assigned to $f as is).
  • echo "$f $(wc -wl < "$f")" uses command substitution ($( ... )) to directly include the output from the enclosed command in the output string passed to echo.
  • Note that the reason that < is used to direct the content of file $f to wc via stdin is that wc would otherwise append the name of the input file to its output (thanks, @R Sahu).
mklement0
  • 382,024
  • 64
  • 607
  • 775