Rename Files in Multiple Directories to the Name of the Directory

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:

  1. 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 the rename, so you aren't preventing any race conditions)
  2. You're passing the opened file object to os.rename, but os.rename takes str, not file-like objects
  3. 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:

Sample Image

Sample Image

This is an example for the output:

Sample Image

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



Leave a reply



Submit