Count only visible files in directory - linux

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.

Related

how to specify 2 file name conditions in shell "find" cmd?

I need to search for all files - in cur dir and all subdirs with a name ending by ~, or a name that start and end by #, delete all files found.
this not working, it does not display found files
find -type f -name "~" or "#*#" ls -a -delete
and this is not working with piping:
find -type f -name "~" or "#*#" | ls -a | -delete
how to specify both conditions?
EDIT: The command line will find files matching the condition, print and then delete them.
Use -o (=or; the implicit default is -a = and) to combine operators and \(/\) to specify operator precedence:
find -type f \( -name "~" -o -name "#*#" \) -delete
You can combine multiple actions, e.g. outputting and deleting at the same time by simply providing all required actions:
find -type f \( -name "~" -o -name "#*#" \) -print -delete
An other option would be to simply filter the results with grep
find -type f | grep -E '(~|#*#)' | xargs rm
That would also allow to build additional steps (like displaying the files) into it

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?

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.

Using find and grep in a specifc file in a specific directory

I have the following directory structure:
./A1
./A2
./A3
./B
./C
In each one of the A* directories I have:
./A*/logs
./A*/test
in the logs directory I have:
./log-jan-1
./log-jan-2
./log-feb-1
How do I grep for a string in all January logs in the A directories?
I tried this, but it did not find the string although it is present in the log files:
find . -type d -name 'A*' print | xargs -n1 -I PATH grep string - PATH/logs/log-jan*
What am I doing wrong?
Why don't you simply use
grep string ./A*/logs/log-jan*
?
If it is not a typo, you should use -print (or -print0) instead of print.
But as find + xargs + grep constructs are hard to debug, you should test in sequence :
find . -type d -name 'A*' -print
find . -type d -name 'A*' -print0 | xargs -0 -n1 -I PATH echo grep string - PATH
and finally :
find . -type d -name 'A*' -print0 | xargs -0 -n1 -I PATH grep string - PATH/logs/log-jan*
In you use case, -print and -print0 should give same results, but for having been burnt with -print, I always use -print0 before xargs

In Linux terminal, how to delete all files in a directory except one or two

In a Linux terminal, how to delete all files from a folder except one or two?
For example.
I have 100 image files in a directory and one .txt file.
I want to delete all files except that .txt file.
From within the directory, list the files, filter out all not containing 'file-to-keep', and remove all files left on the list.
ls | grep -v 'file-to-keep' | xargs rm
To avoid issues with spaces in filenames (remember to never use spaces in filenames), use find and -0 option.
find 'path' -maxdepth 1 -not -name 'file-to-keep' -print0 | xargs -0 rm
Or mixing both, use grep option -z to manage the -print0 names from find
In general, using an inverted pattern search with grep should do the job. As you didn't define any pattern, I'd just give you a general code example:
ls -1 | grep -v 'name_of_file_to_keep.txt' | xargs rm -f
The ls -1 lists one file per line, so that grep can search line by line. grep -v is the inverted flag. So any pattern matched will NOT be deleted.
For multiple files, you may use egrep:
ls -1 | grep -E -v 'not_file1.txt|not_file2.txt' | xargs rm -f
Update after question was updated:
I assume you are willing to delete all files except files in the current folder that do not end with .txt. So this should work too:
find . -maxdepth 1 -type f -not -name "*.txt" -exec rm -f {} \;
find supports a -delete option so you do not need to -exec. You can also pass multiple sets of -not -name somefile -not -name otherfile
user#host$ ls
1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt josh.pdf keepme
user#host$ find . -maxdepth 1 -type f -not -name keepme -not -name 8.txt -delete
user#host$ ls
8.txt keepme
Use the not modifier to remove file(s) or pattern(s) you don't want to delete, you can modify the 1 passed to -maxdepth to specify how many sub directories deep you want to delete files from
find . -maxdepth 1 -not -name "*.txt" -exec rm -f {} \;
You can also do:
find -maxdepth 1 \! -name "*.txt" -exec rm -f {} \;
In bash, you can use:
$ shopt -s extglob # Enable extended pattern matching features
$ rm !(*.txt) # Delete all files except .txt files

Find files older than X and Count them

Using Linux. What I need to do is determine the number of files in a directory(recursively) that are older than DATE and echo that number.
I have:
find /u1/database/prod/arch -type f -mtime +10 -exec ls -laR | wc -l \;
That lists the files fine.
And then I have:
ls -laR | wc -l
Which lets me count the files recursively.
But I can't seem to put them together. I think I need a script to do this but don't know how to do that.
Would love some help
find /u1/database/prod/arch -type f -mtime +10 | wc -l
works here.
You dont need the exec. use -print (or nothing) and find will print a line per file (and handle the recursion)
find /u1/database/prod/arch -type f -mtime +10 -print | wc -l

Resources