How do I find the number of all .txt files in a directory and all sub directories using specifically the find command and the wc command? - linux

So far I have this:
find -name ".txt"
I'm not quite sure how to use wc to find out the exact number of files. When using the command above, all the .txt files show up, but I need the exact number of files with the .txt extension. Please don't suggest using other commands as I'd like to specifically use find and wc. Thanks

Try:
find . -name '*.txt' | wc -l
The -l option to wc tells it to return just the number of lines.
Improvement (requires GNU find)
The above will give the wrong number if any .txt file name contains a newline character. This will work correctly with any file names:
find . -iname '*.txt' -printf '1\n' | wc -l
-printf '1\n tells find to print just the line 1 for each file name found. This avoids problems with file names having difficult characters.
Example
Let's create two .txt files, one with a newline in its name:
$ touch dir1/dir2/a.txt $'dir1/dir2/b\nc.txt'
Now, let's find the find command:
$ find . -name '*.txt'
./dir1/dir2/b?c.txt
./dir1/dir2/a.txt
To count the files:
$ find . -name '*.txt' | wc -l
3
As you can see, the answer is off by one. The improved version, however, works correctly:
$ find . -iname '*.txt' -printf '1\n' | wc -l
2

find -type f -name "*.h" -mtime +10 -print | wc -l
This worked out.

Related

How to get the number of files with a specfic extension in a directory and it's sub directories on Linux terminal?

The question is itself self-explanatory.
I tried the following command I found somewhere on the internet but it shows the number just in the immediate directory and not its subdirectories.
ls -lR ./*.jpg | wc -l
I am searching for all the files with the extension ".jpg" in the current folder and its subdirectories.
find . -type f -name '*.jpg' | wc -l
Find all the files (type f) that have a name that matches '*.jpg' then count them with wc
It's a job for find:
find -name "*.jpg" | wc -l

prevent space from splitting filenames using backticks

Using find to select files to pass to another command using backticks/backquotes, I've noted that filenames that contain spaces will be split, and therfore not found.
Is it possible to avoid this behaviour? The command I issued looks like this
wc `find . -name '*.txt'`
but for example when there is a file named a b c.txt in directory x it reports
$ wc `find . -name '*.txt'`
wc: ./x/a: No such file or directory
wc: b: No such file or directory
wc: c.txt: No such file or directory
When used with multiple files wc will show the output of each file, and a final summary line with the totals of all files. that's why I want to execute wc once.
I tried escaping spaces with sed, but wc produces the same output (splits filenames with spaces).
wc `find . -name '*.txt' | sed 's/ /\\\ /pg'`
Use the -print0 option to find and the corresponding -0 option to xargs:
find . -name '*.txt' -print0 | xargs -0 wc
You can also use the -exec option to find:
find . -name '*.txt' -exec wc {} +
from this very similar question (should I flag my question as a duplicate?) I found another answer to this using bash's ** expansion:
wc **/*.txt
for this to work I had to
shopt -s globstar

Count only visible files in directory

I'm having problem with hidden file in my directory. If I use $(find . -type f | wc -l) it shows 8 files, which counts hidden file too, there should be only 7 files.
Is there anything that could count only visible files?
Ignore the names that start with . by saying:
find . ! -name '.*' -type f | wc -l
From the man page:
! expression
-not expression
This is the unary NOT operator. It evaluates to true if the
expression is false.
If you have filenames with newlines, then you can do using gnu find (as suggested by gniourf gniourf in comments):
find . ! -name '.*' -type f -maxdepth 1 -printf 'x' | wc -c
find . -type f -not -path '*/\.*' | wc -l
-not -path allows you to ignore files with name starting with . (hidden files)
Exclude all files starting with ( . )
find ./ ! -name '\.*' -type f | wc -l
! simply negates the search
If that doesnt work then try this dirty looking solution:
ls -lR | egrep '^(-|l|c|b|p|P|D|C|M|n|s)' | wc -l
Listed all types of files there excluding directories.
You can find the type of files in linux here
without -R of you want to look only in same dir.

Unix display info about files matching one of two patterns

I'm trying to display on a Unix system recursively all the files that start with an a or ends with an a with some info about them: name, size and last modified.
I tried find . -name "*a" -o -name "a*" and it displays all the files okay but when I add -printf "%p %s" it displays only one result.
If you want the same action to apply to both patterns, you need to group them with parentheses. Also, you should add a newline to printf, otherwise all of the output will be on one line:
find . \( -name "*a" -o -name "a*" \) -printf "%p %s\n"
find . -name "*.c" -o -name "*.hh" | xargs ls -l | awk '{print $9,$6,$7,$8,$5}'

how to find files containing a string using egrep

I would like to find the files containing specific string under linux.
I tried something like but could not succeed:
find . -name *.txt | egrep mystring
Here you are sending the file names (output of the find command) as input to egrep; you actually want to run egrep on the contents of the files.
Here are a couple of alternatives:
find . -name "*.txt" -exec egrep mystring {} \;
or even better
find . -name "*.txt" -print0 | xargs -0 egrep mystring
Check the find command help to check what the single arguments do.
The first approach will spawn a new process for every file, while the second will pass more than one file as argument to egrep; the -print0 and -0 flags are needed to deal with potentially nasty file names (allowing to separate file names correctly even if a file name contains a space, for example).
try:
find . -name '*.txt' | xargs egrep mystring
There are two problems with your version:
Firstly, *.txt will first be expanded by the shell, giving you a listing of files in the current directory which end in .txt, so for instance, if you have the following:
[dsm#localhost:~]$ ls *.txt
test.txt
[dsm#localhost:~]$
your find command will turn into find . -name test.txt. Just try the following to illustrate:
[dsm#localhost:~]$ echo find . -name *.txt
find . -name test.txt
[dsm#localhost:~]$
Secondly, egrep does not take filenames from STDIN. To convert them to arguments you need to use xargs
find . -name *.txt | egrep mystring
That will not work as egrep will be searching for mystring within the output generated by find . -name *.txt which are just the path to *.txt files.
Instead, you can use xargs:
find . -name *.txt | xargs egrep mystring
You could use
find . -iname *.txt -exec egrep mystring \{\} \;
Here's an example that will return the file paths of a all *.log files that have a line that begins with ERROR:
find . -name "*.log" -exec egrep -l '^ERROR' {} \;
there's a recursive option from egrep you can use
egrep -R "pattern" *.log
If you only want the filenames:
find . -type f -name '*.txt' -exec egrep -l pattern {} \;
If you want filenames and matches:
find . -type f -name '*.txt' -exec egrep pattern {} /dev/null \;

Resources