Recursively trying to rename files in Mac OS terminal - bash

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*' '' *" \;

Related

How can I delete all files in all subdirectories with a certain name?

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.

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

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