Linux - Find files that do not contain certain characters - linux

I understand that using something like [^a]* will output all the files that do not start with "a".
If I want to echo files that contain at least 5 characters that do not start with "abc" (but can contain "abc" in the middle of the filename), how should I go about doing so?
I have
echo [^abc]?????*
but the output also removes files like "123abc", which I don't quite understand.

You don't indicate which OS your question applies to, but one way to determine the set of matching files on Mac OS X or Linux would be:
find . -maxdepth 1 -type f -name "?????*" | egrep -v "./abc"
Note that this will list only files in the current directory. If you want to include files in subdirectories, you'll need to remove the maxdepth argument.
Also note that these commands are case-sensitive. You'll need to use -iname and -i to make them case-insensitive.
EDIT:
If you really need to use the echo command, the following will work:
echo `find . -maxdepth 1 -type f -name "?????*" | egrep -v "./abc"`

Related

How can i count the number of files with a specific octal code without them showing in shell

I tried using tree command but I didn't know how .(I wanted to use tree because I don't want the files to show up , just the number)
Let's say c is the code for permission
For example I want to know how many files are there with the permission 751
Use find with the -perm flag, which only matches files with the specified permission bits.
For example, if you have the octal in $c, then run
find . -perm $c
The usual find options apply—if you only want to find files at the current level without recursing into directories, run
find . -maxdepth 1 -perm $c
To find the number of matching files, make find print a dot for every file and use wc to count the number of dots. (wc -l will not work with more exotic filenames with newlines as #BenjaminW. has pointed out in the comments. Source of idea of using wc -c is this answer.)
find . -maxdepth 1 -perm $c -printf '.' | wc -c
This will show the number of files without showing the files themselves.
If you're using zsh as your shell, you can do it natively without any external programs:
setopt EXTENDED_GLOB # Just in case it's not already set
c=0751
files=( **/*(#qf$c) )
echo "${#files[#]} files found"
will count all files in the current working directory and subdirectories with those permissions (And gives you all the names in an array in case you want to do something with them later). Read more about zsh glob qualifiers in the documentation.

how to delete files have specific pattern in linux?

I have a set of images like these
12345-image-1-medium.jpg 12345-image-2-medium.png 12345-image-3-large.jpg
what pattern should I write to select these images and delete them
I also have these images that don't want to select
12345-image-profile-small.jpg 12345-image-profile-medium.jpg 12345-image-profile-large.png
I have tried this regex but not worked
1234-image-[0-9]+-small.*
I think bash not support regex as in Javascript, Go, Python or Java
for pic in 12345*.{jpg,png};do rm $pic;done
for more information on wildcards take a look here
So long as you do NOT have filenames with embedded '\n' character, then the following find and grep will do:
find . -type f | grep '^.*/[[:digit:]]\{1,5\}-image-[[:digit:]]\{1,5\}'
It will find all files below the current directory and match (1 to 5 digits) followed by "-image-" followed by another (1 to 5 digits). In your case with the following files:
$ ls -1
123-image-99999-small.jpg
12345-image-1-medium.jpg
12345-image-2-medium.png
12345-image-3-large.jpg
12345-image-profile-large.png
12345-image-profile-medium.jpg
12345-image-profile-small.jpg
The files you request are matched in addition to 123-image-99999-small.jpg, e.g.
$ find . -type f | grep '^.*/[[:digit:]]\{1,5\}-image-[[:digit:]]\{1,5\}'
./123-image-99999-small.jpg
./12345-image-3-large.jpg
./12345-image-2-medium.png
./12345-image-1-medium.jpg
You can use the above in a command substitution to remove the files, e.g.
$ rm $(find . -type f | grep '^.*/[[:digit:]]\{1,5\}-image-[[:digit:]]\{1,5\}')
The remaining files are:
$ l1
12345-image-profile-large.png
12345-image-profile-medium.jpg
12345-image-profile-small.jpg
If Your find Supports -regextype
If your find supports the regextype allowing you to specify which set of regular expression syntax to use, you can use -regextype grep for grep syntax and use something similar to the above to remove the files with the -execdir option, e.g.
$ find . -type f -regextype grep -regex '^.*/[[:digit:]]\+-image-[[:digit:]]\+.*$' -execdir rm '{}' +
I do not know whether this is supported by BSD or Solaris, etc.., so check before turning it loose in a script. Also note, [[:digit:]]\+ tests for (1 or more) digits and is not limited to 5-digits as shown in your question.
Ok I solve it with this pattern
12345-image-*[0-9]-*
eg:
rm -rf 12345-image-*[0-9]-*
it matches all the file names start with 12345-image- then a number then - symbol and any thing after that
as I found it's globbing in bash not regex
and I found this app really use full

"find" specific contents [linux]

I would like to go through all the files in the current directory (or sub-directories) and echoes me back the name of files only if they contain certain words.
More detail:
find -type f -name "*hello *" will give me all file names that have "hello" in their names. But instead of that, I want to search through the files and if that file's content contains "hello" then prints out the name of the file.
Is there a way to approach this?
You can use GNU find and GNU grep as
find /path -type f -exec grep -Hi 'hello' {} +
This is efficient in a way that it doesn't invoke as many grep instances to as many files returned from find. This works in an underlying assumption that find returns a set of files for grep to search on. If you are unsure if the files may not be available, as a fool-proof way, you can use xargs with -r flag, in which case the commands following xargs are executed only if the piped commands return any results
find /path -type f | xargs -r0 grep -Hi 'hello'

find -exec doesn't recognize argument

I'm trying to count the total lines in the files within a directory. To do this I am trying to use a combination of find and wc. However, when I run find . -exec wc -l {}\;, I recieve the error find: missing argument to -exec. I can't see any apparent issues, any ideas?
You simply need a space between {} and \;
find . -exec wc -l {} \;
Note that if there are any sub-directories from the current location, wc will generate an error message for each of them that looks something like that:
wc: ./subdir: Is a directory
To avoid that problem, you may want to tell find to restrict the search to files :
find . -type f -exec wc -l {} \;
Another note: good idea using the -exec option . Too many times people pipe commands together thinking to get the same result, for instance here it would be :
find . -type f | xargs wc -l
The problem with piping commands in such a manner is that it breaks if any files has spaces in it. For instance here if a file name was "a b" , wc would receive "a" and then "b" separately and you would obviously get 2 error messages: a: no such file and b: no such file.
Unless you know for a fact that your file names never have any spaces in them (or non-printable characters), if you do need to pipe commands together, you need to tell all the tools you are piping together to use the NULL character (\0) as a separator instead of a space. So the previous command would become:
find . -type f -print0 | xargs -0 wc -l
With version 4.0 or later of bash, you don't need your find command at all:
shopt -s globstar
wc -l **/*
There's no simple way to skip directories, which as pointed out by Gui Rava you might want to do, unless you can differentiate files and directories by name alone. For example, maybe directories never have . in their name, while all the files have at least one extension:
wc -l **/*.*

Search a file in Unix

I need to search a file in unix which starts with "catalina"
find ... what to be used effectively -name, -exec ? Whats the expression
Also I need to show few files at a time, then show some more. There are huge set of log files in there. I know there is some expression, but forgot...
find /path/to/search/in -name 'catalina*'
Use iname to match case-insensitively.
To not be overwhelmed with a long list of files, filter through less (append |less). You can also use more instead of less.
If catalina is the file name, then use
find -name 'catalina*'
If catalina is the first word contained in the file, then use
find -type f | xargs head -v -n 1 | grep -B 1 -A 1 -e '^catalina'

Resources