Rename files in multiple directories to the name of the directory
The result can be achieved with a bash for loop and mv
:
for subdir in *; do mv $subdir/file.txt $subdir.txt; done;
Note that the solution above will not work if the directory name contains spaces. Related link.
Another solution based on comments (that works for directories having spaces in the name as well):
find . -type d -not -empty -exec echo mv \{\}/file.txt \{\}.txt \;
Rename files in multiple directories
You have a few problems:
- You're opening a file for no apparent reason (it confirms the file exists and is readable at
open
time, but even with an open handle, the name could be moved or deleted between that and therename
, so you aren't preventing any race conditions) - You're passing the opened file object to
os.rename
, butos.rename
takesstr
, not file-like objects - You're doing a lot of "magic" manipulations of the path, instead of using appropriate
os.path
functions
Try this to simplify the code. I included some inline comments when I'm doing what your example does, but it doesn't make a lot of sense (or it's poor form):
for path in files: # path, not f; f is usually placeholder for file-like object
filedir, filename = os.path.split(path)
parentdir = os.path.dirname(filedir)
# Strip parentdir name to get 'Sample_*_' per provided code; is this what you wanted?
# Question text seems like you only wanted the '*' part.
sample_id = parentdir.replace('results_', '').replace('hg38_hg19', '')
# Large magic numbers are code smell; if the name is a fixed name,
# just use it directly as a string literal
# If the name should be "whatever the file is named", use filename unsliced
# If you absolutely need a fixed length (to allow reruns or something)
# you might do keepnamelen = len('NoAdapter_len25.truncated_sorted.fastq')
# outside the loop, and do f[-keepnamelen:] inside the loop so it's not
# just a largish magic number
back = filename[-38:]
new_name = sample_id + back
new_path = os.path.join(filedir, new_name)
rename(path, new_path)
Rename files in Multiple Folders with os
You can use the functionality of os.path
to extract the file extension and use it for renaming your file.
I recreated your directories with .png
and .jpg
images, and running your code, both folder1 and folder2 worked. There must be a typo or something else causing the problem.
Here is the function you could use instead:
## rename.py
import os
def main():
folders = ["folder1", "folder2"]
for folder_name in folders:
for count, filename in enumerate(os.listdir(folder_name)):
_, ext = os.path.splitext(os.path.basename(filename))
newfilename = f"{folder_name} {str(count)}{ext}"
src = f"{folder_name}/{filename}"
dst = f"{folder_name}/{newfilename}"
os.rename(src, dst)
if __name__ == '__main__':
main()
How to rename multiple directories into corresponding file names in bash
This can be done using bash regular expression matching with capturing groups.
Code
read -r -d '' input <<END
MCIA-0-control_20170509
MCIA-1-control_20170509
MCIA-2-control_20170509
MCIA-03-timesport_20170717
MCIA-04-timesport_20170717
MCIA-05-timesport_20170717
MCIA-6-timesport_20170717
END
for name in $input; do
[[ $name =~ ^MCIA-0*([[:digit:]]+)-(control|timesport)_[[:digit:]]+$ ]] &&
echo mv "$name" "subj-${BASH_REMATCH[1]}-${BASH_REMATCH[2]}"
done
Output
mv MCIA-0-control_20170509 subj-0-control
mv MCIA-1-control_20170509 subj-1-control
mv MCIA-2-control_20170509 subj-2-control
mv MCIA-03-timesport_20170717 subj-3-timesport
mv MCIA-04-timesport_20170717 subj-4-timesport
mv MCIA-05-timesport_20170717 subj-5-timesport
mv MCIA-6-timesport_20170717 subj-6-timesport
Explanation
^
: Match start of string.MCIA-
: Match the current directory prefix.0*
: Optionally match any number of leading zeroes. These do not go into a capturing group, because we want to discard them.([[:digit:]]+)
: After discarding leading zeroes, capture one or more remaining digits into the first capture group.-
: Match and discard the additional hyphen.(control|timesport)
: Capture either "control" or "timesport" into the second capture group._[[:digit:]]+
: Match all the rest.$
: Match end of string.
If the input string is a match, then build up the mv
command with the destination as the concatenation of "subj", the first capture group and the second capture group. For testing purposes, my code sample uses echo
to print the command instead of running it. You can expand as necessary with validation, existence checks, etc. as you are already doing in your original code sample.
For more details on regular expressions in bash, see Advanced Bash-Scripting Guide - 18.1. A Brief Introduction to Regular Expression.
Changing name of the file to parent folder name
So, based on what I understood, you have a single file in each folder. You would like to rename the file with the same folder name and preserve the extension.
import os
# Passing the path to your parent folders
path = r'D:\bat4'
# Getting a list of folders with date names
folders = os.listdir(path)
for folder in folders:
files = os.listdir(r'{}\{}'.format(path, folder))
# Accessing files inside each folder
for file in files:
# Getting the file extension
extension_pos = file.rfind(".")
extension = file[extension_pos:]
# Renaming your file
os.rename(r'{}\{}\{}'.format(path, folder, file),
r'{}\{}\{}{}'.format(path, folder, folder, extension))
I have tried it on my own files as follows:
This is an example for the output:
I hope I got your point. :)
Rename multiple files in multiple sub folders using python
You need to use the file in the dir where it is.
import os
# assign directory
directory = "all Student folders"
# iterate over files
for root, _, files in os.walk(directory):
for file_name in files:
if file_name == "Work.pdf":
os.rename(f"{root}/{file_name}", f"{root}/homework1.pdf")
else:
new_name = file_name.replace(f"Work", "homework")
os.rename(f"{root}/{file_name}", f"{root}/{new_name}")
how to rename multiple files in a multiples directories whit the name of each directory
You could loop over the result of find
:
for f in $(find . -type "f" -printf "%P\n"); do
mv $f $(dirname $f)/$(basename $(dirname $(readlink -f $f)) | tr '/' '_')_$(basename $f);
done
explanation: recursively find all regular files, starting at the current directory, and print the relative path (one per line) without a leading .
, storing it in a variable f
. For each f
, rename to [the directory portion of f
]/
[the basename of the directory name of f
(ie. the name of the parent directory where f
is located), with all /
characters replaced by _
]_
[the filename potion of f
]
Using find
and the extra bit of complexity in $(dirname $f)/$(basename $(dirname $(readlink -f $f))
is to allow more than 1 level of nested directories.
Related Topics
How to Control a User Systemd Using 'Systemctl --User' After Sudo Su - Myuser
Bash: Difference Between "Export K=1" VS. "K=1"
How to Check If Hadoop Daemons Are Running
Possible to Use a .Dll on Linux
How to Sleep for 1 Second Between Each Xargs Command
View a Particular Line of a File Denoted by a Number
Linux Command to Empty All Files of a Directory
Arch Linux - Apt-Get Update Equivalent Command
How to Recursively Copy a Directory into Another and Replace Only the Files That Have Not Changed
Link a Static Library to a Shared One During Build
Define Alias That References Other Aliases
How to Make Debian Package Install Dependencies
Centos Directory Structure as Tree
How to Capture Network Packets Per Pid
The Return Code from 'Grep' Is Not as Expected on Linux
How to Find or Calculate a Linux Process's Page Table Size and Other Kernel Accounting