Linux - find
Files can be found under Linux in many different ways, using the find tool is one of the best ways to find files.
locate
Searches for a filename in a system.
updatedb # update database with all filenames on a filesystem locate 'filename*.conf' # search
find
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
default path is the current directory; default expression is -print
Find a string within a file but not follow symlinks / grep don't follow sym-links
find . -type f | xargs grep "string-to-search"
Find a file with a specific name
find /etc -iname -perm 777 'program.c' # / -start searching from the root directory, by default it will be recursive search also within sub-directories # -name - filename search # -iname -case insensitive sensitive filename search # -type f -perm 777 -file with specific permissions
Searching paths -path
To search within a path we can use the -path
flag instead of the -name
flag. Let’s try to find any files whose path contains the word session
.
$ find . -path \*session\* #find files and directories ./actionpack/lib/action_dispatch/middleware/session/mem_cache_store.rb ./actionpack/lib/action_dispatch/request/session.rb ./actionpack/test/dispatch/request/session_test.rb ./actionpack/test/dispatch/session ./actionpack/test/dispatch/session/abstract_store_test.rb $ find . -path \*session\* -type d #finds only directories ./actionpack/lib/action_dispatch/middleware/session ./actionpack/test/dispatch/session
Find files bigger than
This command below finds files bigger than 999999B only on / root filesystem, locking up to a single file achieves by using -xdev switch
find / -xdev -size +999999 -exec ls -lhd {} \;
Find with time
find /home -cmin +10 -name '*.conf' # created more than 10 minutes ago find /home -amin -10 -name '*.conf' # accessed less than 10 minutes ago find /home -mmin 10 -name '*.conf' # modified exactly 10 minutes ago find /home -ctime +2 -name '*.conf' # created more then 2 days ago find /home -atime -2 -name '*.conf' # accessed less than 2 days ago find /home -mtime 2 -name '*.conf' # modified exactly 2 days ago
Find with size
find /mp3collection -name '*.mp3' -size -5000k # have a size less than 5000 Kilobytes (< 5MB) find / -size +10000k # any file that is larger than 10000k (> 10MB) find / -size +10000k # any file that is larger than 10M (> 10MB)
Find mounting points
$ find / -mount -name 'win*
This command searches for files starting with the letters 'win' in their filenames. The only difference is that the mounted filesystems would not be searched for this time. This is useful when you have your Windows partitions mounted by default. And a search for 'win' might return many files on those partitions, which you may not be really interested in. This is only one use of -mount parameter.
Boolean operators such as AND, OR and NOT
Boolean operators such as AND, OR and NOT make find an extremely useful tool. The 1st command searches within the directory /mp3-collection for files that have their names beginning with 'Metallica' and whose size is greater than 10000 kilobytes (> 10 MB). The 2nd command searches in the same directory as above case but only for files that are greater than 10MB, but they should not have 'Metallica' as the starting of their filenames. The 3rd command searches in the same directory for files that begin with 'Metallica' in their names or all the files that are greater than 10 MB in size.
find /mp3-collection -name 'Metallica*' -and -size +10000k find /mp3-collection -size +10000k ! -name "Metallica*" find /mp3-collection -name 'Metallica*' -or -size +10000k
Performing operations
Find and execute command (-exec)
The exec option is probably the most important feature of the find tool. The exec command allows you to execute a particular command on the results of the find command. A simple demonstration of this feature is shown below. Its upto your imagination to make maximum use of this feature. Suppose you wanted to see the details of the files (read, write, execute permission, file size, owner etc..) that have been returned as a search result you could do the following
# find string within find files results find . -type f -exec grep -l 'string-to-search' {} \; # find and delete files modified more than 5 days ago find /home -mtime +5 -exec rm {} \;
The words following the -exec option is the command that you want to execute i.e. ls -l in this case.
-exec command {} \;
curly brackets expand to a single matching file, line by line, a backslash\
escapes command termination;
can also be used';'
so won't need escaping.
Find directory's and execute command to change permissions
$ find . -type d -exec chmod 0755 {} \;
Find and -delete
The find tool also has the built-in ability to execute certain commands. The -delete
flag will, as its name suggests, delete all files and directories that match the pattern. Here the -print
flag is used to show the files that will be deleted.
find ./logs -mtime +14 -type f -print -delete # delete files older than 14 days find ./logs -type f -name \*.log -print -delete # delete files '*.log'
Find and -exec | rename
sudo apt-get install rename #it's Perl version of rename util $ find . -iname "*foo*" -print0 | xargs -0 rename "s/<old>/<new>/" # find files mattching fileglob *foo* # -print0 :- print space delimited instead line by line # pass each found file_path to Perl's rename utility to do 's' substitution of pattern '<old>' to '<new>' # the '/' is here as a delimiter
- xargs
Because Unix filenames can contain blanks and newlines, this default behaviour is often problematic; filenames containing blanks and/or newlines are incorrectly processed by xargs
. In these situations it is better to use the -0
option, which prevents such problems. When using this option you will need to ensure that the program which produces the input for xargs
also uses a null character as a separator. If that program is GNU find
the -print0
option does this for you.
Rename using bash expansion
for i in *.ogg; do mv "$i" "${i/Beatles/TheBeatles}"; done # following expansion is doing replace in string
Find and update symlink content
This works for both updating a directory in symlink or part of target name.
find . -type l -lname '*old*' -printf '%l\0%p\0' | sed -z 's|old|NEW|;n' | xargs -r0n2 ln -sfT # -type l :- symlink # -lname :- target of symlink matches a pattern vars_app.tf -> ../../../stacks/old/vars_old.tf #before vars_app.tf -> ../../../stacks/NEW/vars_NEW.tf #after
Find a file using grep and sed it
$ grep -rl <pattern> * | xargs sed -i 's/<old>/<new>/g' # -rl :- find and display files matching <pattern> # pass each file path to sed to do substitution
ack
and ag
- grep on steroids
Tools for searching large code bases. Ack and Ag are 99% feature compatible with each other, so you can use them interchangeably. Ag is significantly faster than Ack, and it has built-in version control system (VCS) awareness.
Both Ack and Ag treat the search term as a regular expression by default.
# Install CentOS, Amazon Linux AMI yum search silver_searcher sudo yum install -y the_silver_searcher.x86_64 # Install Ubuntu $ sudo apt-get install ag ack ag LOG #search for 'LOG' string any file in CWD and display matching lines ag ^LOG #regular expression search (default) ag -Q LOG #literal string search ag LOG /var/log/ #search within given path # -l -list files that contain matching pattern # -i -case insensitive search # -G <file_matching_pattern> -scope search to files names that match a pattern # --ignore-dir -ignore path(s) in search
Old ack-grep
tool
sudo apt-get install ack-grep ack-grep 'Cisco1941'