Rename files adding their parent folder name
Solution 1
In a small python script, renaming files recursively (folders as well as sub folders):
#!/usr/bin/env python3
import shutil
import os
import sys
dr = sys.argv[1]
for root, dirs, files in os.walk(dr):
for f in files:
shutil.move(root+"/"+f, root+"/"+root.split("/")[-1]+f)
How to use
- Copy the script into an empty file, save it as
rename_files.py
Run it with the directory as an argument:
python3 /path/to/rename_files.py /directory/with/files
Note
As always, first try on a sample!
Explanation
The script:
- Walks through the directories, looking for files.
If files are found, it splits the path to the file with the delimiter "/", keeping the last in the row (which is the parent's folder name) , to be pasted before the file's name:
root.split("/")[-1]
Subsequently, move the file to the renamed one:
shutil.move(root+"/"+f, root+"/"+root.split("/")[-1]+f)
Solution 2
You can do this with rename
:
rename -n 's/(.*)\//$1\/$1/' */*
This command needs to be started in the directory directly above the directories you want to process. It will first only list the changes for you to check, if you're happy with the results run it without -n
to perform the renaming.
Example run
$ tree
.
└── SOCH NC KT 633-ROYAL BLUE-MULTI
├── 1.jpg
├── 2.jpg
└── 3.jpg
$ rename 's/(.*)\//$1\/$1/' */*
$ tree
.
└── SOCH NC KT 633-ROYAL BLUE-MULTI
├── SOCH NC KT 633-ROYAL BLUE-MULTI1.jpg
├── SOCH NC KT 633-ROYAL BLUE-MULTI2.jpg
└── SOCH NC KT 633-ROYAL BLUE-MULTI3.jpg
Explanation
rename 's/(.*)\//$1\/$1/' */*
s/a/b/
–s
ubstitutea
byb
(.*)\/
– take everything until (excl.) the last slash saving it as group 1 and substitute it by$1\/$1
– group 1 (dir name), a slash and group 1 again (file name prefix)
Solution 3
Using only shell (bash
) with a little help from mv
:
#!/bin/bash
shopt -s globstar ##globstar will let us match files recursively
files=( /foo/bar/**/*.jpg ) ##Array containing matched files, mention where to search and what files here
for i in "${files[@]}"; do
d="${i%/*}" ##Parameter expansion, gets the path upto the parent directory
d_="${d##*/}" ##gets the name of parent directory
f="${i##*/}" ##gets the file name
echo mv "$i" "$d"/"${d_}""$f" ##renaming, remove echo after confirming what will be changed and you are good
done
Example:
$ shopt -s globstar
$ files=( /foo/bar/**/*.jpg )
$ for i in "${files[@]}"; do d="${i%/*}"; d_="${d##*/}"; f="${i##*/}"; echo mv "$i" "$d"/"${d_}""$f"; done
mv /foo/bar/KT/633-ROYAL/4.jpg /foo/bar/KT/633-ROYAL/633-ROYAL4.jpg
mv /foo/bar/KT/633-ROYAL/5.jpg /foo/bar/KT/633-ROYAL/633-ROYAL5.jpg
mv /foo/bar/KT/633-ROYAL/6.jpg /foo/bar/KT/633-ROYAL/633-ROYAL6.jpg
mv /foo/bar/KT/633-ROYAL/BLUE-MULTI/1.jpg /foo/bar/KT/633-ROYAL/BLUE-MULTI/BLUE-MULTI1.jpg
mv /foo/bar/KT/633-ROYAL/BLUE-MULTI/2.jpg /foo/bar/KT/633-ROYAL/BLUE-MULTI/BLUE-MULTI2.jpg
mv /foo/bar/KT/633-ROYAL/BLUE-MULTI/3.jpg /foo/bar/KT/633-ROYAL/BLUE-MULTI/BLUE-MULTI3.jpg
Solution 4
Here's a small example of how that can be done form the directory you want to edit.
$> ls
file1.txt file2.txt file3.txt
$> pwd
/home/xieerqi/testing_dir
$> find . -type f -printf "%f\0" | \
> while IFS="" read -d "" filename ; do \
> echo $filename ${PWD##*/}_$filename ; done
file2.txt testing_dir_file2.txt
file1.txt testing_dir_file1.txt
file3.txt testing_dir_file3.txt
Replace echo
with mv
or cp
for copying or moving as necessary
Related videos on Youtube
Neo
Updated on September 18, 2022Comments
-
Neo over 1 year
I want to rename file name with its parent folder name, adding the folder name before the current name.
for example:
Folder structure
SOCH NC KT 633-ROYAL BLUE-MULTI | | 1.jpg | | 2.jpg | | 3.jpg
Expected Result
SOCH NC KT 633-ROYAL BLUE-MULTI | |_SOCH NC KT 633-ROYAL BLUE-MULTI1.jpg | |_SOCH NC KT 633-ROYAL BLUE-MULTI2.jpg | |_SOCH NC KT 633-ROYAL BLUE-MULTI3.jpg SOCH NC KT 710-BLACK-MULTI
Could anyone advise how this can be done in a .sh file? Is there any utility is available to do the operation?
-
Videonauth about 8 years@JacobVlijm the same can aswell be done in bash with
for F in *; do cd $F; for D in *; do mv -Tv $D $F$D; done; cd ..; done
. Just mentioning so you can add it to your answer as another possible solution given youre in the parent directory where the directories reside which you want to work down. -
Jacob Vlijm about 8 years@Videonauth thanks, but the command doesn't really work as expected :)
-
Videonauth about 8 years@JacobVlijm weird, i tested it before i posted it and it did its job. i made a folder test with two foldesr a nd b inside it, switched into the test folder, created in a and b files with touch(just to test) and the command renamed each file to have the foldername in fron of the filename in both folders.
-
wjandrea over 5 yearsYou could enable nullglob (
shopt -s nullglob
) and use a dir-only glob ("$workdir"/**/
) to get rid ofif [[ -d "$folder" ]] ...
. Also note that you should always quote variables like$workdir
. -
wjandrea over 5 yearsIf you get an error "Argument list too long", you can use
find . -mindepth 2 -maxdepth 2 -type f -exec rename -n 's/(.*)\//$1\/$1/' {} \;
instead. This is adapted from askubuntu.com/a/1081902/301745 -
wjandrea over 5 yearsPersonally I'd write the Perl expression with a different delimiter like
|
(pipe), to avoid escaping slashes:'s|(.*)/|$1/$1|'