Using Bash how would I get all file names (not paths) of files containing ".cpp", given a root folder to recursively-check?
Just use find:
find /root/folder/to/check -name '*.cpp' -printf "%P\n"
You can use for that purpose -printf option of find command with the following parameter:
%f File's name with any leading directories removed (only the last element).
so the full command may look like this:
find / -type f -name "*.cpp" -printf "%f\n"
Related
On a unix server, I'm trying to figure out how to remove a file, say "example.xls", from any subdirectories that start with v0 ("v0*").
I have tried something like:
find . -name "v0*" -type d -exec find . -name "example.xls" -type f
-exec rm {} \;
But i get errors. I have a solution but it works too well, i.e. it will delete the file in any subdirectory, regardless of it's name:
find . -type f -name "example.xls" -exec rm -f {} \;
Any ideas?
You will probably have to do it in two steps -- i.e. first find the directories, and then the files -- you can use xargs to make it in a single line, like
find . -name "v0*" -type d | \
xargs -l -I[] \
find [] -name "example.xls" -type f -exec rm {} \;
what it does, is first generating a list of viable directory name, and let xargs call the second find with the names locating the file name within that directory
Try:
find -path '*/v0*/example.xls' -delete
This matches only files named example.xls which, somewhere in its path, has a parent directory name that starts with v0.
Note that since find offers -delete as an action, it is not necessary to invoke the external executable rm.
Example
Consider this directory structure:
$ find .
.
./a
./a/example.xls
./a/v0
./a/v0/b
./a/v0/b/example.xls
./a/v0/example.xls
We can identify files example.xls who have one of their parent directories named v0*:
$ find -path '*/v0*/example.xls'
./a/v0/b/example.xls
./a/v0/example.xls
To delete those files:
find -path '*/v0*/example.xls' -delete
Alternative: find only those files directly under directory v0*
find -regex '.*/v0[^/]*/example.xls'
Using the above directory structure, this approach returns one file:
$ find -regex '.*/v0[^/]*/example.xls'
./a/v0/example.xls
To delete such files:
find -regex '.*/v0[^/]*/example.xls' -delete
Compatibility
Although my tests were performed with GNU find, both -regex and -path are required by POSIX and also supported by OSX.
The following command cann't work when the file name contains extended attributes.
cd ~/Library/Containers
find . -type f -name "*.xml"
It returned nothing. But
less com.apple.TextEdit/Data/Music/iTunes/iTunes\ Music\ Library.xmlary.xml
The xml file is there.
In order to follow the symbolic links in the directory hierarchy, you need to use the -L option to find:
find -L . -type f -name "*.xml"
I have a directory which contains a number of files (no subdirectories). I wish to find these files. The following gets me close:
$ find docs
docs
docs/bar.txt
docs/baz.txt
docs/foo.txt
I don't want the directory itself to be listed. I could do this instead:
$ find docs -type f
docs/bar.txt
docs/baz.txt
docs/foo.txt
Using a wildcard seems to do the trick as well:
$ find docs/*
docs/bar.txt
docs/baz.txt
docs/foo.txt
My understanding is that these work in different ways: with -type, we're providing a single path to find, whereas in the latter case we're using wildcard expansion to pass several paths to find. Is there a reason to favour one approach over the other?
You have a UNIX tag, and you example has a *. Some versions of find have a problem with that.
If the directory has no subdirectories.
FYI.
Generally the first parms to find has to be a directory or a list of directories
find /dir1 /dir2 -print
Find is recursive - so it will follow each directory down listing every thing, symlinks, directories, pipes, and regular files. This can be confusing. -type delimits your search
find /dir1 /dir2 -type f -print
You can also have find do extra output example: have it rm files older than 30 days for example:
find /dir1 /dir2 -type f -mtime +30 -exec rm {} \;
Or give complete infomation
find /dir1 /dir2 -type f -mtime +30 -exec ls -l {} \;
find /dir1 /dir2 -type f -mtime +30 -ls # works on some systems
To answer your question: because find can be dangerous ALWAYS fully specify each directory , file type ,etc., when you are using a nasty command like rm. You might have forgotten your favorite directory is also in there. Or the one used to generate your paycheck. Using a wildcard is ok for just looking around.
Using *
find /path/to/files -type f -name 'foo*'
-- tics or quotes around strings with a star in them in some UNIX systems.
find docs -type f
will get you a listing of every non-directory file of every subdirectory of docs
find docs/*
will get you a listing of every file AND every subdirectory of docs
I've found the following line of code in a script. Could someone explain me what does this following line of code means?
Basically, the purpose of this line is find a set of files to archive. Since I am not familiar with bash scripts, it is difficult for me to understand this line of code.
_filelist=`cd ${_path}; find . -type f -mtime ${ARCHIVE_DELAY} -name "${_filename}" -not -name "${_ignore_filename}" -not -name "${_ignore_filename2}"`
Let's break it down:
cd ${_path} : changes to the directory stored in the ${_path} variable
find is used to find files based on the following criteria:
. : look in the current directory and recurse through all
sub-directories
-type f: look for regular files only (not directories)
-mtime ${ARCHIVE_DELAY} : look for files last modified
${ARCHIVE_DELAY}*24 hours ago
-name "${_filename}": look for files which have name matching ${_filename}
-not -name "${_ignore_filename}" : do not find files which have
name matching ${_ignore_filename}
-not -name "${_ignore_filename2}" : do not find files which have
name matching ${_ignore_filename2}
All the files found are stored in a variable called _filelist.
The backtick (`) symbol assigns to the variable the output of the command.
Your script is assigning to $_filelist what you get by:
Changing directory to $_path
Finding in the current directory (.) files (-type f) where
Name is $_filename (a pattern, I suppose)
Name is not $_ignore_filename or $_ignore_filename2
I think you could as well change that to find ${_path} ... without the cd, but please try it out.
_filelist=`somecode`
makes the variable _filelist contain the output of the command somecode.
Somecode, in this case, is mostly a find command, which searches recursively for files.
find . -type f -mtime ${ARCHIVE_DELAY} -name "${_filename}" -not -name "${_ignore_filename}" -not -name "${_ignore_filename2}"
find .
searches the current dir, but this was just before changed to be _path.
-type f
only searches in ordinary files (not dirs, sockets, ...)
-mtime
specifies the modification time of that files, to be the same as ${ARCHIVE_DELAY}
-name explains
itself, has to be "${_filename}"
-not name
explains itself too, I guess.
So the whole part sets the variable filelist to files, found by some criterias: name, age, and type.
I have a directory with roughly 100000 files in it, and I want to perform some function on all files beginning with a specified string, which may match tens of thousands of files.
I have tried
ls mystring*
but this returns with the bash error 'Too many arguments'. My next plan was to use
find ./mystring* -type f
but this has the same issue.
The code needs to look something like
for FILE in `find ./mystring* -type f`
do
#Some function on the file
done
Use find with a wildcard:
find . -name 'mystring*'
ls | grep "^abc"
will give you all files beginning (which is what the OP specifically required) with the substringabc.
It operates only on the current directory whereas find operates recursively into sub folders.
To use find for only files starting with your string try
find . -name 'abc'*
If you want to restrict your search only to files you should consider to use -type f in your search
try to use also -iname for case-insensitive search
Example:
find /path -iname 'yourstring*' -type f
You could also perform some operations on results without pipe sign or xargs
Example:
Search for files and show their size in MB
find /path -iname 'yourstring*' -type f -exec du -sm {} \;