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
Related
I have been trying to use the command line to delete all files in all subdirectories with the name s_1_1102_c.jpg.
This question is similar to what I need How to remove folders with a certain name but it is removing directories and I only want to delete the files with the name s_1_1102_c.jpg.
I will need to remove this file from 260 subdirectories under the L001 directory. My directory structure is like this:
L001
C5.1
s_1_1101_a.jpg
s_1_1101_c.jpg
s_1_1101_g.jpg
s_1_1101_t.jpg
s_1_1102_a.jpg
s_1_1102_c.jpg
s_1_1102_g.jpg
s_1_1102_t.jpg
s_1_1103_a.jpg
s_1_1103_c.jpg
s_1_1103_g.jpg
s_1_1103_t.jpg
C6.1
s_1_1101_a.jpg
s_1_1101_c.jpg
s_1_1101_g.jpg
s_1_1101_t.jpg
s_1_1102_a.jpg
s_1_1102_c.jpg
s_1_1102_g.jpg
s_1_1102_t.jpg
s_1_1103_a.jpg
s_1_1103_c.jpg
s_1_1103_g.jpg
s_1_1103_t.jpg
Ultimately I need to remove several files from all subdirectories (s_1_1101_g.jpg, s_1_1101_t.jpg, s_1_1102_a.jpg, s_1_1102_c.jpg, s_1_1102_g.jpg, s_1_1102_t.jpg). So maybe there is a way to provide a list of the file names I need to delete.
How can I delete these files?
find . -name "s_1_1102_c.jpg" -exec rm -f {} \;
Note: This will find and delete the file in any subdirectory of the current one. So you could execute it in L001 or wherever else you want to do this.
for i in s_1_1101_g.jpg s_1_1101_t.jpg s_1_1102_a.jpg s_1_1102_c.jpg s_1_1102_g.jpg s_1_1102_t.jpg; do
echo rm L001/*/"$i";
done
If output looks fine, remove echo.
The final method I used to delete my files was given by #Peter - Reinstate Monica
for f in s_1_1101_t.jpg s_1_1102_a.jpg s_1_1102_c.jpg s_1_1102_g.jpg s_1_1102_t.jpg s_1_1103_a.jpg s_1_1103_c.jpg s_1_1103_g.jpg s_1_1103_t.jpg s_1_1104_a.jpg s_1_1104_c.jpg s_1_1104_g.jpg s_1_1104_t.jpg s_1_2101_g.jpg s_1_2101_t.jpg s_1_2102_a.jpg s_1_2102_c.jpg s_1_2102_g.jpg s_1_2102_t.jpg s_1_2103_a.jpg s_1_2103_c.jpg s_1_2103_g.jpg s_1_2103_t.jpg s_1_2104_g.jpg s_1_2104_t.jpg; do find /hpc/home/L001 -name $f -delete; done
I was concerned that my file list would be too long but it worked in this situation.
I have a many subfolders with files containing the text mainLine in them. I want to strip that text and rename all files recursively.
For example I'm trying to rename log12 mainLine.txt to log12.txt, I'm trying the following code:
find . -exec rename -nvs '* mainLine*' '' * {} +
But I'm getting files which contain that pattern as unchanged.
There are many versions of rename, and to my knowledge none of them are installed by default in Mac OS; but the options you used suggest you are using one which expects file names to rename as the third and subsequent arguments. You apparently copy/pasted it from somewhere without understanding it. You should replace the * with the files you want to rename, or better yet, run it once per directory with the wildcard intact.
find . -type d -execdir sh -c "rename -nvs '* mainLine*' '' *" \;
I have a rather interesting problem that I am trying to find the optimal solution for. I am creating an file autocompletion backend for Emacs. This means that I am using the linux find command to get files and directories.
The backend is given a file with a partially completed path (e.g. /usr/folder/foo) and I want to grab all files and directories that could match the partial path for two directories down (e.g. for example it could provide foo_bar/, foo_bar/bar, foo_bar/baz, foo_bar/bat/ foo_baz). So far I have only been to break this down into 3 steps
find all files in the current directory that may match the prefix
find foo* -type f -maxdepth 1
collect all possible directories we may want to look through
find foo* -type d -maxdepth 1
use each of those directories to make 2 more calls to find (I need to be able to differentiate between files and directories)
find foo_bar/ -type d -maxdepth 1
find foo_bar/ -type f -maxdepth 1
This solution involves a lot of calls to find (especially because the last step has to be called for every matching directory). This makes getting candidates slow, especially in large file systems. Ideally I would like to only make one call to get all the candidates. But I have not found a good way to do that. Does anyone know an optimal solution?
looking though the find manpage, I ended up using -printf.
find -L foo* -maxdepth 1 -printf '%p\t%y\n'
gives me everything I needed. only one command, differentiate between files and directories, search depth, etc.
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
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:
{.[!.]*,..?*}