renaming folders using a .txt file
I'm working in my terminal using bash trying to rename the folders:
1
2
3
4
5
I'd like to rename them according to a.txt file:
a 2
c 3
d 5
e 1
b 4
The order in the .txt file is completely random. I'm hoping to find a way where I can rename the folder so they become:
1 > e
2 > a
3 > c
4 > b
5 > d
Is there any way to do this?
Thanks a lot!
Solution 1:
You could use xargs
with mv
:
xargs -r -a /path/to/file.txt -L1 mv
(assuming you're in the directory where the files are located).
xargs
converts input to arguments for a command.
-
-a foo
to read input fromfoo
. -
-L1
to use exactly one line of input per command invocation. -
-r
to avoid running the command if the line is empty
For example, using echo mv
instead of mv
to show the commands being run:
$ xargs -r -a foo.txt -L1 echo mv
mv a 2
mv c 3
mv d 5
mv e 1
mv b 4
You can also use the -p
option to make xargs
confirm before running the command:
$ xargs -r -p -a foo.txt -L1 mv
mv a 2 ?...n
mv c 3 ?...n
mv d 5 ?...y
mv e 1 ?...mv: cannot stat ‘d’: No such file or directory
n
mv b 4 ?...
Solution 2:
Assuming the names in the list do not include spaces, other than between the names, the script below will rename folders from a textfile recursively. It will read the lines of the file, split them into two (new name, old name), rename occuring folders which are named by the second string in the line, into the first string in the line.
It will do this, as mentioned recursively, from bottom to top in the directory tree. This prevents issues in the script, attempting to rename folders in possibly already renamed parent folders.
#!/usr/bin/env python
import os
import shutil
# -- set the (absolute) path to the targeted folder below
dr = "/home/jacob/Bureaublad/testfolder"
# -- set the path to the textfiles below
ren = "/home/jacob/Bureaublad/testfolder/renfile.txt"
renlist = [cpl for cpl in [l.split() for l in open(ren).readlines()] if cpl]
currnames = [r[1] for r in renlist]
for root, dirs, files in os.walk(dr, topdown = False):
for dr in dirs:
try:
# look up the name, pass if not in the list
i = currnames.index(dr)
except ValueError:
pass
else:
newname = renlist[i][0]
shutil.move(root+"/"+dr, root+"/"+newname)
How to use
- Copy the script into an empty file (in a plain text editor), save it as
rename.py
- In the head section of the script, set the real paths to the textfile and the directory
-
run it by the command (in a terminal):
python /path/to/rename.py
Explanation
The script:
- creates a list of name- couples: newname/oldname
- using python's
os.walk()
, it looks through your directories recursively, from bottom to top. - If the folder's name matches the second item of a name couple, it renames the folder into the first name.
- If the folder's name is not listed, it will be untouched.
Solution 3:
There is one entry per line in the a.txt
file, so the names listed do not contain \n
(new line) char, right?
A line contains 2 names separated with a space char, so the names do not contain space char, right? (or another possibility would be to use fixed length for the names listed).
Give a try to this, if the names do not contain neither \n
nor space
chars:
awk '{printf("%s\0%s\0",$2,$1)}' a.txt | xargs -0 -L 2 mv
awk
is used to reverse the order of names in lines read from a.txt
file. \0
is used to separate the names when they are printed to standard output.
xargs
reads the standard input:
-
-0
:\0
is used as separator for the elements read from standard input -
-L 2 mv
:mv
command is invoked with 2 parameters at a time.
The test:
$ ls -al
total 40
drwxrwxr-x 7 stacko stacko 4096 May 31 11:25 .
drwxrwxr-x 21 stacko stacko 12288 May 31 11:23 ..
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 1
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 2
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 3
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 4
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 5
-rw-rw-r-- 1 stacko stacko 20 May 31 11:24 a.txt
$ cat a.txt
a 2
c 3
d 5
e 1
b 4
$ awk '{printf("%s\0%s\0",$2,$1)}' a.txt | xargs -0 -L 2 mv -v
'2' -> 'a'
'3' -> 'c'
'5' -> 'd'
'1' -> 'e'
'4' -> 'b'
$ ls -al
total 40
drwxrwxr-x 7 stacko stacko 4096 May 31 11:26 .
drwxrwxr-x 21 stacko stacko 12288 May 31 11:23 ..
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 a
-rw-rw-r-- 1 stacko stacko 20 May 31 11:24 a.txt
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 b
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 c
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 d
drwxrwxr-x 2 stacko stacko 4096 May 31 11:25 e
Solution 4:
In the simple case you show above, where each line has two "words", the target directory and the new name, and where neither can contain any whitespace, you can simply do:
while read -r from to; do mv "$from" "$to"; done < file
That will read each line in file
assign the first string (until the first whitespace) to $from
and the rest of the line to $to
and then run mv
on each of them.