Bash find files and display path function - bash

I'm writing a function in my .bashrc file which helps me find files according to the string which I pass as an argument to the function:
# ~/.bashrc
function search {
find . -iname "*$1*" -printf "%f\n"
}
This function is good. It prints out all the files with the given string under the directory I'm in, and also all the files with the same given string in all subdirectories. Only it just prints out each file and not its path.
If I for example have a folder containing some sub-folders and files this function would be so much more helpful if it would print out the path to each file if they are located under any sub-folders.
F.ex. if I have a folder named Folder/ and a few sub-folders named whatever_num and running search thisandthat would spit out a list looking something like this:
$ search thisandthat
some-file-containing-thisandthat-in-its-filename.ext
whatever_1/path/to/some-file-containing-thisandthat-in-its-filename.ext
whatever_2/path/to/some-file-containing-thisandthat-in-its-filename.ext
So my queston is: How can I modify my search function so that it prints out the path to the files I might be searching for?
Thank you!

function search {
find `pwd` -iname "*$1*"
}

Change the find line to:
find . -iname "*$1*" -printf "$(pwd)/%P\n"

Thanks to #JKB and to #acro444. Their answers helped me modify my search function. I am posting my answer since I decided to go with a slightly different solution than the once they posted but it's thanks to their contribution:
# ~/.bashrc
function search {
find . -iname "*$1*" -printf "%P\n"
}
I do it this way because I don't care about seeing /home/myusername/... all the time in front of the rest of the path. I know I am in my /home/username/somefolder directory and seeing always /home/username/..... for each file that might come up is just too much "noise" I think and unnecessary.
Thank you again for the help!
Cheers!

Related

Processing only the current directory with find/prune

I've been reading up on find's -prune action. One common task I do is to process only the files of a directory, ignoring all directories.
Prune, from what I've learned, is great for ignoring directories if you know their names (or wildcards matching their names). But what if you don't know their names (or a pattern that matches files as well as directories)?
I found that -maxdepth achieves what I'm trying to do. I'm just wondering what the equivalent -prune approach might be.
For example, say I want to process all the files of my home directory, but not recurse into any subdirectory. Let's say my directory structure and files look like this (directories ending in '/'):
~/tmpData.dat
~/.bashrc
~/.vimrc
~/.Xdefaults
~/tmp/
~/tmp/.bashrc
~/bkups/.bashrc
~/bkups/.vimrc
~/bkups/.Xdefaults
~/bkups/tmpData.dat
.. what would be the correct find/prune command?
OK, I found my own solution. I simply specify pattern(s) that match everything in my
home directory ('~/*' for example). But in order to include all my dot files (.bashrc,
etc.), I have to use two patterns; one for non-dotted filenames and one for the files
starting with dots:
find ~/* ~/.* -type d -prune -o -type f -print

Find a file in Cygwin

I use find -name "nametofind" in cygwin to search for a file, but it does not give me any result, even when the file I want to search exists in the current directory. What am I doing wrong? Thanks.
As the comment mentioned more succinctly, you need to tell find which directory you want to search. If you it is the current directory, you should use ..
find . -name "nametofind"
It appears that the OP was trying to either match a partial file name or a file name with a different case. As #devnull mentioned in his comment, the correct solution for either case is to use the following.
find . -iname '*nametofind*'

replace all files with same name

I have a file in multiple folder called PFSound.js
I've updated it so I want to replace all PFSound.js files in those directories for the new one,
is there a way to do it in just one time?
Mac or windows is ok
Thanks!!
On Mac/Linux, you can do this:
find . -type f -name "PFSound.js" -exec cp path/to/new/PFSound.js {} \;
assuming you wish to do that from the current directory downwards and that the new PFSound.js is located somewhere else.
That says.... find, starting at dot (the current directory) all things of type "file" with the name "PFSound.js", and for each one you find, execute the copy command and copy the new PFSound.js into the same place you just found an old one.
you can use a python script for this .
import os
newfilename="the_new_name"
def renamethefile(folderPath):
for fileOrFolder in os.listdir(folderPath):
if os.path.isdir(fileOrFolder) :
renamethefile(fileOrFolder)
continue
else:
os.rename(fileOrFolder, newfilename)
renamethefile("/path/to/the/folder");
i hope this help you .

Bash script to find file older than X days, then subsequently delete it, and any files with the same base name?

I am trying to figure out a way to search a directory for a file older than 365 days. If it finds a match, I'd like it to both delete the file and locate any other files in the directory that have the same basename, and delete those as well.
File name examples: 12345.pdf (Search for) then delete, 12345_a.pdf, 12345_xyz.pdf (delete if exist).
Thanks! I am very new to BASH scripting, so patience is appreciated ;-))
I doubt this can be done cleanly in a single pass.
Your best bet is to use -mtime or a variant to collect names and then use another find command to delete files matching those names.
UPDATE
With respect to your comment, I mean something like:
# find basenames of old files
find .... -printf '%f\n' | sort -u > oldfiles
for file in ($<oldfiles); do find . -name $file -exec rm; done

Bash globbing - autoexpand for a few specific cases?

I understand that the wildcard * (by itself) will expand in such a way that it means "all non-hidden files in the current folder" with hidden files being those prefixed by a period.
There are two use cases that I would think are useful, but I don't know how to properly do:
How can you glob for... "All files in the current folder, including hidden files, but not including . or .."?
How can you glob for... "All hidden files (and only hidden files) in the current folder, but not including . or .."?
To expand on paviums answer and answer the second part of your question, all files except . and .. could be specified like this:
{.[!.]*,*}
Depending on your exact use case it might be better to set the dotglob shell option, so that bash includes dotfiles in expansions of * by default:
$ shopt -s dotglob
$ echo *
.tst
The Bash Cookbook suggests a solution to your 2nd requirement.
.[!.]*
as a way of specifying 'dot files' but avoiding . and ..
Of course, ls has the -A option, but that's not globbing.
Combining sth and pavium answers
# dot files but avoiding . and ..
.[!.]*
# all files but avoiding . and ..
{.[!.]*,*}
To meet your first case:
echo {.,}[^.]*
or
echo {.,}[!.]*
Edit:
This one seems to get everything, but is shorter than ephemient's
echo {.*,}[^.]*
By "all files" and "all hidden files" do you mean files-only, or do you mean both files and directories? Globbing operates on names irrespective of it belonging to a file or a directory. The other folks give good answers for using globbing to find hidden vs non-hidden names, but you may want to turn to the find command as an easier alternative that can distinguish between the types.
To find "All files in the current folder, including hidden files, but not including . or ..":
find . -type f
To find "All files and directories in the current folder, including hidden files, but not including . or ..":
find . ! -name .
To find "All hidden files (and only hidden files) in the current folder, but not including . or ..":
find . -name '.*' -type f
To find "All hidden files and directories (and only hidden files and directories) in the current folder, but not including . or ..":
find . -name '.*' ! -name .
Note that by default find will recurse through subdirectories, too, so if you want to limit it to only the current directory you can use:
find . -maxdepth 1 -type f
So, even though this is old - without using shopt, this doesn't seem to have been answered fully. But, expanding on what has been given as answers so far, these work for me:
1:
{*,.[!.]*,..?*}
2:
{.[!.]*,..?*}

Resources