Unix display info about files matching one of two patterns - linux

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}'

Related

Can't find a file by pattern [duplicate]

I am having a hard time getting find to look for matches in the current directory as well as its subdirectories.
When I run find *test.c it only gives me the matches in the current directory. (does not look in subdirectories)
If I try find . -name *test.c I would expect the same results, but instead it gives me only matches that are in a subdirectory. When there are files that should match in the working directory, it gives me: find: paths must precede expression: mytest.c
What does this error mean, and how can I get the matches from both the current directory and its subdirectories?
Try putting it in quotes -- you're running into the shell's wildcard expansion, so what you're acually passing to find will look like:
find . -name bobtest.c cattest.c snowtest.c
...causing the syntax error. So try this instead:
find . -name '*test.c'
Note the single quotes around your file expression -- these will stop the shell (bash) expanding your wildcards.
What's happening is that the shell is expanding "*test.c" into a list of files. Try escaping the asterisk as:
find . -name \*test.c
From find manual:
NON-BUGS
Operator precedence surprises
The command find . -name afile -o -name bfile -print will never print
afile because this is actually equivalent to find . -name afile -o \(
-name bfile -a -print \). Remember that the precedence of -a is
higher than that of -o and when there is no operator specified
between tests, -a is assumed.
“paths must precede expression” error message
$ find . -name *.c -print
find: paths must precede expression
Usage: find [-H] [-L] [-P] [-Olevel] [-D ... [path...] [expression]
This happens because *.c has been expanded by the shell resulting in
find actually receiving a command line like this:
find . -name frcode.c locate.c word_io.c -print
That command is of course not going to work. Instead of doing things
this way, you should enclose the pattern in quotes or escape the
wildcard:
$ find . -name '*.c' -print
$ find . -name \*.c -print
Try putting it in quotes:
find . -name '*test.c'
I see this question is already answered. I just want to share what worked for me. I was missing a space between ( and -name. So the correct way of chosen a files with excluding some of them would be like below;
find . -name 'my-file-*' -type f -not \( -name 'my-file-1.2.0.jar' -or -name 'my-file.jar' \)
I came across this question when I was trying to find multiple filenames that I could not combine into a regular expression as described in #Chris J's answer, here is what worked for me
find . -name one.pdf -o -name two.txt -o -name anotherone.jpg
-o or -or is logical OR. See Finding Files on Gnu.org for more information.
I was running this on CygWin.
You can try this:
cat $(file $( find . -readable) | grep ASCII | tr ":" " " | awk '{print $1}')
with that, you can find all readable files with ascii and read them with cat
if you want to specify his weight and no-executable:
cat $(file $( find . -readable ! -executable -size 1033c) | grep ASCII | tr ":" " " | awk '{print $1}')
In my case i was missing trailing / in path.
find /var/opt/gitlab/backups/ -name *.tar

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

Find all files without broken links

I need to find all source files including linked files, but avoid broken links.
I have a c/c++ source code area, with some files linked to files to other directories and I want to index them using cscope. When there are broken links, cscope gives an error:
cscope: cannot find file /...file....
What I need actually is to create a clean cscope.files without broken linked files.
What I'm currently doing is:
find $code_path -type f -name '*.h' -o -name '*.c' -o -name '*.cpp' >> cscope.files
find with little help from file to get the filetype, and print-ing the files that do not have broken symbolic link target:
find "$code_path" -type f -name '*.h' -o -name '*.c' -o -name '*.cpp' \
-exec sh -c 'file "$1" | grep -qv broken' _ {} \; -print
This has the caveat of processing one file at a time.
if you do not have any filename with whitespace(s) or any control character(s), you can leverage find ... -exec {} + capability of dealing with maximum number of file(s) in one go without triggering ARG_MAX, and getting the desired filenames with awk:
find "$code_path" -type f -name '*.h' -o -name '*.c' -o -name '*.cpp' \
-exec file {} + | awk '!/broken/ {print $1}'
Side note: Quote your variable expansions to prevent word splitting and pathname expansion from taking place on the expansion.

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.

Need help writing compound linux query

Trying to write my first compund linux query and running into some gaps in knowledge.
The idea is to find all the file that may be either .doc or .txt as well as search the contents for the text clown.
So I started off with searching from the root as such.
$find /
Then I added the wildcard for filename.'
$find / -name '*.doc'...uhh oh
First question. How do I specify or? Is it with pipe | or double pipe || or...? and do I need to repeat the -name parameter like this?
$find / -name '*.doc' || -name '*.txt'
Second ? do I add the grep for the string after / before...?
$find / -name '*.doc' || -name '*.txt' grep -H 'cat' {} \
Finally is there a place where I can validate syntax / run like SQLFiddle?
TIA
'Or' in find is -o
You have to specify the find type again though. So something like:
find / -name *.doc -o -name *.txt
You can simply put your grep command in front, so long as you encase your find command in backticks:
grep 'whatever' `find / -name *.doc -o -name *.txt`
There's a reasonably nice guide to find here
You want something like this:
find / \( -name \*.doc -o -name \*.txt \) -exec grep clown {} \; -print
you specify or with -o within \( \), you run grep in a -exec and you can validate the syntax in a bash shell.
Try:
(find ./ -name "*.txt" -print0 2>/dev/null ; find ./ -name "*.doc" -print0 2>/dev/null) | xargs -0 grep clown

Resources