Replace a file if path of the file contains a string in Linux [duplicate] - linux

I know how to find files using
find . -name "file_name"
But if I am given one part of a path, say "folder1/subfolder2/", how do I get all the full path that contains this partial path?
Example
partial path: folder1/subfolder2/
desire result:
/bob/folder1/subfolder2/yo/
/sandy/folder1/subfolder2/hi/

Use the -path option:
find . -path '*/folder1/subfolder2/*'

You may do it like below:
find . -path "*folder1/folder2" -prune -exec find {} -type f -name file.txt \;
With -prune you don't recurse after first match in a directory

This one worked for me (using bash)
ls -l /**/folder1/subfolder2/**

I came up with this, other solutions did not work for me,
find1 is a function
find1 ()
{
for file in `find -name $1`;
do
full_path=$PWD/$file;
echo $full_path;
done
}

If you dont want to stay posix-compliant, at least on Linux you can also use the -regex (and -regextype) option for this purpose.
For instance:
find folder/ -regextype posix-extended -regex "(.*/)?deer/(.*/)?beer"
will match
folder/deer/beer
folder/deer/dir/forest/beer/
folder/forest/deer/dir/forest/beer/
etc.
See linux man for details.

Related

Linux find catalogs and print only names

i wanna search for the catalogs which have the "program" in their names and echo these names in console. I have wrote this, but isn't working:
find usr -type d -name "program" -exec echo {}
The error is find: missing argument to `-exec'.
find usr -type d -name "program"
usr/lib64/libreofice/program
How to fix my command?
Some tiny example with the * wildcard.
find /my/path -name "*program*"
If you don' use wildcards, it will try to find exactly the files named program. Also, echoing is done automatically, you don't need the exec command.
Update
Answering to your comment. You can get the base name (name without the path) with:
find . -name "*program*" -exec basename {} \;

Exclude range of directories in find command

I have directory called test which has sub folders in the date range like 01,02,...31. This all sub folders contain .bz2 files in it. I need to search all the files with .bz2 extension using find command but excluding particular range of directories. I know about find . -name ".bz2" -not -path "./01/*", but writing -not -path "./01/*" would be so pathetic if I would want to skip 10 directories. So how would I skip 01..19 subdirectories in my find command ?
You can use wildcards in the pattern for the option -not -path:
find ./ -type f -name "*.bz2" -not -path "./0*/*" -not -path "./1*/*
this will exclude all directories starting with 0 or 1. Or even better:
find ./ -type f -name "*.bz2" -not -path "./[01]*/*"
Firstly, you can help find by using -prune rather than -not -path - that will avoid even looking inside the relevant directories.
To your main point - you can build a wildcard for your example (numeric 01 to 19):
find . -path './0[1-9]' -prune -o -path './1[0-9]' -prune -o -print
If your range is less convenient (e.g. 05 to 25) you might want to build the range into a bash variable, then interpolate that into the find command:
a=("-path ./"{05..25}" -prune -o")
find . ${a[*]} -print -prune
(you might want to echo "${a[*]}" or printf '%s\n' ${a[*]} to see how it's working)
For me, I found the find command as a standalone tool somehow cumbersome. Therefore, I always end up using a combination of find just for the recursive file search and grep to make the actual exculsion/inclusion stuff. Finally I hand over the results to a third command which will perform the actions, like rm to remove files for example.
My generic command would look something like this:
find [root-path] | grep (-v)? -E "cond1|cond2|...|condN" | [action-performing-tool]
root-path is where to start the search recursively
add -v option is used to invert the matching results.
cond1 - condN, the conditions for the matching. When -v is involed then this are the conditions to not match.
the action-performing-tool does the actual work
For example you want to remove all files not matching some conditions in the current directory:
find . -not -name "\." | grep -v -E "cond1|cond2|cond3|...|condN" | xargs rm -rf
As you can see, we are searching in the current directory indicated by the dot as root-path: then we want to invert the matching results, because we want all files not matching our conditions: and finally we pass all files found to rm in order to delete them: I add -rf to recursive/force delete all files. I used the find command with -not -name "." to exclude the current directory indicated normally by dot.
For the actuall question: Assume we have a directory using .git and .metadata directory and we want to exclude them in our search:
find . -not -name "\." | grep -v -E ".git|.metadata" | [action-performing-tool]
Hope that helps!
If you wan to exclude child directory under parent directory then this might be useful:
E.g.- You have parent directory "ParentDir" and it has two child directories "Child1, Child2". You wan to read files from "Chiled2" only and skip "Child1". Then this will help.
find ./ParentDir ! -path "./ParentDir/Child1*" -name *.<extention>

Find all files contained into directory named

I would like to recursively find all files contained into a directory that has name “name1” or name “name2”
for instance:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name1/subfolder/file1s.a
structure/of/dir/name1/subfolder/file2s.b
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
structure/of/dir/name2/subfolder/file1s.a
structure/of/dir/name2/subfolder/file2s.b
structure/of/dir/name3/name1.a ←this should not show up in the result
structure/of/dir/name3/name2.a ←this should not show up in the result
so when I start my magic command the expected output should be this and only this:
structure/of/dir/name1/file1.a
structure/of/dir/name1/file2.b
structure/of/dir/name1/file3.c
structure/of/dir/name2/file1.a
structure/of/dir/name2/file2.b
structure/of/dir/name2/file3.c
I scripted something but it does not work because it search within the files and not only folder names:
for entry in $(find $SEARCH_DIR -type f | grep 'name1\|name2');
do
echo "FileName: $(basename $entry)"
done
If you can use the -regex option, avoiding subfolders with [^/]:
~$ find . -type f -regex ".*name1/[^/]*" -o -regex ".*name2/[^/]*"
./structure/of/dir/name2/file1.a
./structure/of/dir/name2/file3.c
./structure/of/dir/name2/subfolder
./structure/of/dir/name2/file2.b
./structure/of/dir/name1/file1.a
./structure/of/dir/name1/file3.c
./structure/of/dir/name1/file2.b
I'd use -path and -prune for this, since it's standard (unlike -regex which is GNU specific).
find . \( -path "*/name1/*" -o -path "*/name2/*" \) -prune -type f -print
But more importantly, never do for file in $(find...). Use finds -exec or a while read loop instead, depending on what you really need to with the matching files. See UsingFind and BashFAQ 20 for more on how to handle find safely.

Recursively find files with a specific extension

I'm trying to find files with specific extensions.
For example, I want to find all .pdf and .jpg files that's named Robert
I know I can do this command
$ find . -name '*.h' -o -name '*.cpp'
but I need to specify the name of the file itself besides the extensions.
I just want to see if there's a possible way to avoid writing the file name again and over again
Thank you !
My preference:
find . -name '*.jpg' -o -name '*.png' -print | grep Robert
Using find's -regex argument:
find . -regex '.*/Robert\.\(h\|cpp\)$'
Or just using -name:
find . -name 'Robert.*' -a \( -name '*.cpp' -o -name '*.h' \)
find -name "*Robert*" \( -name "*.pdf" -o -name "*.jpg" \)
The -o repreents an OR condition and you can add as many as you wish within the braces. So this says to find all files containing the word "Robert" anywhere in their names and whose names end in either "pdf" or "jpg".
As an alternative to using -regex option on find, since the question is labeled bash, you can use the brace expansion mechanism:
eval find . -false "-o -name Robert".{jpg,pdf}
This q/a shows how to use find with regular expression: How to use regex with find command?
Pattern could be something like
'^Robert\\.\\(h|cgg\\)$'
As a script you can use:
find "${2:-.}" -iregex ".*${1:-Robert}\.\(h\|cpp\)$" -print
save it as findcc
chmod 755 findcc
and use it as
findcc [name] [[search_direcory]]
e.g.
findcc # default name 'Robert' and directory .
findcc Joe # default directory '.'
findcc Joe /somewhere # no defaults
note you cant use
findcc /some/where #eg without the name...
also as alternative, you can use
find "$1" -print | grep "$#"
and
findcc directory grep_options
like
findcc . -P '/Robert\.(h|cpp)$'
Using bash globbing (if find is not a must)
ls Robert.{pdf,jpg}
Recurisvely with ls: (-al for include hidden folders)
ftype="jpg"
ls -1R *.${ftype} 2> /dev/null
For finding the files in system using the files database:
locate -e --regex "\.(h|cpp)$"
Make sure locate package is installed i.e. mlocate

Output directory name from linux find command

How do I get the name of a folder from a linux find commnad.
I have a command like this:
find /root/wgetlog -name -type d -empty
Whic produces the following results:
/root/wgetlog/smil3
/root/wgetlog/smil5
/root/wgetlog/smil4
how do I get just the name of the folder:
Example:
smil3
smil4
smil5
find /root/wgetlog -type d -empty -printf "%f\n"
If all you need is a relative path, then
{ pushd /root/wgetlog/; find . -name -type d -empty; popd; }
is the approach, especially if you do care about subdirectories of /root/wgetlog/*.
Use basename:
find /root/wgetlog -type d -empty -exec basename {} \;
You don't need -name.
You could also use sed to filter out the leading elements of each path:
$ find /usr/bin -type d
/usr/bin
/usr/bin/multiarch-i386-linux
/usr/bin/multiarch-x86_64-linux
/usr/bin/gda_trml2pdf
/usr/bin/gda_trml2html
...
$ find /usr/bin -type d | sed 's|.*/||'
bin
multiarch-i386-linux
multiarch-x86_64-linux
gda_trml2pdf
gda_trml2html
...
This might be more portable than using the -printf option of find, although that should not be an issue if you stick to Linux.
Disclaimer: this will fail horribly if you have newlines in your file/folder names. On the other hand, this snippet is probably not the only thing that would fail in that case...

Resources