I have a parent folder that contains multiple folders within it. Then, each of these nested folders contains 4 files that make up a GIS shapefile and have different extensions (i.e., ".dbf", ".prj", ".shp", and ."shx"). I am new to coding (outside of R) and do not know whether this can be automated with Python or if I need to run a shell script (I'm working on a windows). I have very rudimentary coding schools so documentation would be great (and/or suggestions of "dummy" sites to read).
Here is an example of the current file structure (showing the four files I want to rename with the subfolder name):
Parent Folder: "Raptors"
Subfolder: "Falco_peregrinus"
File 1: "ra03310.dbf"
File 2: "ra03310.prj"
File 3: "ra03310.shp"
File 4: "ra03310.shx"
Here is what I would like the four files to be renamed to:
File 1: Falco_peregrinus.dbf
File 2: Falco_peregrinus.prj
File 3: Falco_peregrinus.shp
File 4: Falco_peregrinus.shx
Thanks.
For a batch file solution
#echo off
for /d %%a in ("c:\...\Raptors\*") do ren "%%~fa\*.*" "%%~na.*"
For each folder inside the parent one, rename all the files inside the folder to the name of the folder but keeping the extension
for command is used to iterate over the list of folders (/d) under the parent folder. For each of the folders, the replaceable parameter %%a will hold a reference to the subfolder and the code in the do clause is executed for each one.
The code in the do clause executes a ren command, for all the files under the subfolder (%%~fa is the folder being processed with full path), changing its name to the name of the folder (%%~na).
edited The answer is not completely correct. While the basic idea of using only one ren command to rename all the files under each folder is probably the fastest way, the way ren command handles wildcards makes this code fail if the folder name contains dots. To be sure the code will not fail, it is necessary to iterate over the files, renaming each one
for /d %%a in ("c:\...\Raptors\*") do for %%b in ("%%~fa\*") do ren "%%~fb" "%%~nxa%%~xb"
For each folder (%%a), for each file inside the folder (%%b), rename the file to the name of full folder name (%%~nxa) with the extension of the file (%%~xb)
You could use almost any programming language (probably including R) to do this. Python is a good choice here because it has such friendly syntax.
A extremely simple script that will solve your problem might look like this
import os
import os.path
'''
Given a file name, returns a pair with the name and extension (hello.txt => [hello,txt])
'''
def split_name(file_name):
return file_name.rsplit('.',1)
'''
Recursively renames files in subdirectories of base_directory so each file is named the subdirectory name plus the extension
WARNING! You will be very sad if you have multiple files with the same extension in any of those folders
def rename_file(base_directory):
#Get the folder name for base_directory (c:\users\foobar => foobar)
directory_name = os.basename(base_directory)
#List the files in base_directory
for path in os.listdir(base_directory):
old_name = base_directory + '/' + path
#If the path points to a file, rename it directory name + '.' + extension
if os.path.isfile(old_name):
new_name = base_directory + '/' + directory_name + '.' + split_name(path)[1]
if not os.path.exists(new_name):
os.rename(old_name,new_name)
else:
print("ERROR:"+new_name+" exists")
else:
#If it's a subfolder, recursively call rename files on that directory.
rename_files(old_name)
Also, I stongly suggest Learn Python The Hard Way by Zed Shaw and Dive Into Python by Mark Pilgrim
a simple windows command can solve your problem. Read HELP FOR and the try this in the Windows command line:
for /d %a in (*) do #for %b in (%a\*) do #ren %a\%b %a%~xb
let's analyze it
the first for will iterate over all (*) the directories /d and for each found, passed in %a the second for will iterate over all the files it contains (%a\*) and for each file found %b it will do rename ren it %a\%b with the name of the folder it is contained in %a keeping the same extension it had %~xb.
This can be done with batch only, I publish this script only to demonstrate how easy this is in Ruby
# enumerate all subfolders of raptors
Dir.glob("raptors/**/*/") do |folder|
# remember the prefix
pre = File.basename(folder)[/.+_/]
# enumerate all files under this folder
Dir.glob("#{folder}*.*") do |file|
File.rename(file, "#{File.dirname(file)}/#{pre}#{File.basename(file)}")
end
end
There is another answer with python code, this code changed my GIS file names based on folder name very well:
Thanks #Martin Evans.
Related
I have been able to successfully run the below code on an individual file, but I would like to find a way to have it run so that it loops through all the files shown in a directory. I believe that loops are possible within CMD.exe, but I am not having any success. Any help would be greatly appreciated.
"C:\Program Files (x86)\LibreOffice 5\program\scalc.exe" --convert-to DBF --infilter="csv:44,34,76,1,1/2/2/2/3/2/4/2/5/2/6/2/7/2/8/2/9/2/10/2/11/2/12/2/13/2/14/2/15/2/16/2/17/2/18/2/19/2/20/2/21/2/22/2/23/2/24/2/25/2/26/2/27/2/28/2/29/2/30/2/31/2/32/2/33/2/34/2/35/2/36/2/37/2/38/2/39/2/40/2/41/2/42/2/43/2/44/2/45/2/46/2/47/2/48/2/49/2/50/2/51/2/52/2/53/2/54/2/55/2/56/2/57/2/58/2/59/2/60/2/61/2/62/2/63/2/64/2/65/2/66/2/67/2/68/2/69/2/70/2/71/2/72/2/73/2/74/2/75/2/76/2/77/2/78/2/79/2/80/2/81/2/82/2/83/2/84/2/85/2/86/2/87/2/88/2/89/2/90/2/91/2/92/2/93/2/94/2/95/2/96/2/97/2/98/2/99/2/100/2/101/2/102/2/103/2/104/2/105/2/106/2/107/2/108/2/109/2/110/2/111/2/112/2/113/2/114/2/115/2/116/2/117/2/118/2/119/2/120/2/121/2/122/2/123/2/124/2/125/2/126/2/127/2/128/2/129/2/130/2/131/2/132/2/133/2/134/2/135/2/136/2,0,false,false" C:\Users\jdavidson\Desktop\DBFCONVERT\57826001_JQSAMPLE.csv --outdir C:\Users\jdavidson\desktop\complete
If you have any ideas for how I might be able to achieve this it be a huge help. I am working to build this as part of a larger workflow and make it repeatable.
UPDATE
I was able to iterate(Loop) through all of the files in my directory by creating a batch file and placing it within the directory that I am going to be using for converting moving forward
for /r %%i in (*.csv) do "C:\Program Files (x86)\LibreOffice 5\program\scalc.exe" --convert-to DBF --infilter="csv:44,34,76,1,1/2/2/2/3/2/4/2/5/2/6/2/7/2/8/2/9/2/10/2/11/2/12/2/13/2/14/2/15/2/16/2/17/2/18/2/19/2/20/2/21/2/22/2/23/2/24/2/25/2/26/2/27/2/28/2/29/2/30/2/31/2/32/2/33/2/34/2/35/2/36/2/37/2/38/2/39/2/40/2/41/2/42/2/43/2/44/2/45/2/46/2/47/2/48/2/49/2/50/2/51/2/52/2/53/2/54/2/55/2/56/2/57/2/58/2/59/2/60/2/61/2/62/2/63/2/64/2/65/2/66/2/67/2/68/2/69/2/70/2/71/2/72/2/73/2/74/2/75/2/76/2/77/2/78/2/79/2/80/2/81/2/82/2/83/2/84/2/85/2/86/2/87/2/88/2/89/2/90/2/91/2/92/2/93/2/94/2/95/2/96/2/97/2/98/2/99/2/100/2/101/2/102/2/103/2/104/2/105/2/106/2/107/2/108/2/109/2/110/2/111/2/112/2/113/2/114/2/115/2/116/2/117/2/118/2/119/2/120/2/121/2/122/2/123/2/124/2/125/2/126/2/127/2/128/2/129/2/130/2/131/2/132/2/133/2/134/2/135/2/136/2,0,false,false" C:\Users\jdavidson\Desktop\DBFCONVERT\57826001_JQSAMPLE.csv --outdir C:\Users\jdavidson\desktop\complete %%i
Note that I used a for Loop to achieve what I wanted.
for /r %%i in ('list directory if command not being run in specific directory already; you can also but * for all files in directory or *.ext for the extension of only certain files) do 'add in command %%i
Option 1: You can actually convert multiple documents with just one execution of Open/Libre Office.. without a loop. Just use a wildcard, eg:
"C:\Program Files (x86)\LibreOffice 5\program\scalc.exe" --convert-to DBF mydir\*.csv
Option 2: I assume that Windows has a limit on the number of files you can pass in that way.. not sure what that limit is.. but if you exceed that limit, you can use this python program I wrote to do this just a few days ago.. as part of a project I am still working on. In my case I am converting .doc to .odt, and obviously my directories aren't the same as yours. But it would be quite easy for you to adjust this to your needs... One thing I wanted to do with mine is to check for the existence of the converted file and skip it if it exists.. so that if a few new files are added it can be run again to convert them without redoing them all...
The docpath should be set to the location of your files, and soffice to the pathname of your Calc exe.. and if you leave things the way I have them, that's where the program puts the converted files too.. and checks for their existence. Also, I walk the path looking for input files.. so if for whatever reason you have your files in different subdirectories, it will find them and put the conversion in the same directory.
import os, sys, re, subprocess
docpath = 'doc'
soffice = 'C:\Program Files\LibreOffice 5\program\soffice.exe'
convert = '"%s" --headless --convert-to odt --outdir "%s" "%s"'
def plog(fmt = '', *args):
sys.stdout.write(fmt % args)
sys.stdout.flush()
def log(fmt = '', *args):
plog((fmt + '\n'), *args)
def convert():
odtfiles = []
for subdir, dirs, files in os.walk(docpath):
for file in files:
if not file.endswith('.doc'):
continue
docfile = os.path.join(subdir, file)
odtfile = re.sub(r"\.doc$", ".odt", docfile)
plog("%s -> %s: " % (docfile, odtfile))
if not os.path.isfile(odtfile):
plog('Converting.. ')
subprocess.check_output(convert % (soffice, docpath, docfile), shell=True)
log('OK.')
odtfiles.append(odtfile)
return odtfiles
odtfiles = convert()
Just install Python27.. and set the convert string to have the correct settings for your conversion. Along with a few other changes that should be pretty easy.. but if you need help, ask in comments.
I have 2 identical folder trees, let's call them C:\First and C:\Second, with many subfolders. C:\First has many XML files in many sub and sub-sub folders. C:\Second just has the folder tree created.
I want to go through all XML files in C:\First\* and put it in it's equivalent place in C:\Second.
But first I want to check if a file with the same name exists in the C:\Current folder (no subfolders there), in which case I will copy the one from C:\Current to the proper sub-sub-sub folder in C:\Second.
In other words, I want to copy the whole structure and files from C:\First to C:\Second but I want to take the latest version that may or may not exist in C:\Current. And, in C:\Current there are many files I don't care about.
Example:
C:\Current has these files:
a.xml
b.xml
1.xml
c.xml
d.xml
e.xml
2.xml
f.xml
g.xml
3.xml
In C:\First I have a.xml, b.xml, c.xml, d.xml, e.xml, f.xml, g.xml spread out in its sub-folders.
I hope I'm not being too confusing...
When a problem is properly stated, the same problem description may serve as specifications to write the program. In your case, you have this description:
I want to go through all XML files in C:\First* and put it in it's
equivalent place in C:\Second.
But first I want to check if a file with the same name exists in the
C:\Current folder
The "But first" doesn't serve to write a program. You just need to write the first things in first place! For example:
I want to go through all XML files in C:\First*. I want to check if a
file with the same name exists in the C:\Current folder in which case
I will copy the one from C:\Current to the proper sub-sub-sub folder
in C:\Second. Otherwise put the file from C:\First in it's equivalent
place in C:\Second.
The pseudo-code below is an example of how your original problem description may be translated into a program:
rem I have 2 identical folder trees, let's call them C:\First and C:\Second, with many subfolders.
rem C:\First has many XML files in many sub and sub-sub folders. C:\Second just has the folder tree created.
rem I want to go through all XML files in C:\First\*
for /R inside C:\First with all *.XML files do (
rem But first I want to check if a file with the same name exists in the C:\Current folder (no subfolders there)
if exist "C:\Current folder\place here just the name of the file from the for command" (
rem in which case I will copy the one from C:\Current to the proper sub-sub-sub folder in C:\Second.
set properFolder=place here the sub-sub-sub folder from the for command
set properFolder=change "C:\First" by "C:\Second" in properFolder
copy "C:\Current folder\just the name" "!properFolder!"
) else (
rem ... and put it in it's equivalent place in C:\Second.
set properFolder=place here the sub-sub-sub folder from the for command
set properFolder=change "C:\First" by "C:\Second" in properFolder
copy "the file from for command" "!properFolder!"
)
)
If you analyze this code you will realize that the lines that get properFolder are the same in both parts, so a simpler method would be to get properFolder just one time before the if command.
You may use this pseudo-code as starting point to write your Batch file.
Hi, I have many zip files located at g:\toto. These zips contain some files. I would like to extract all zip in a same directory (g:\toto\extracted) then rename various files of the zip.
Example 1 :
www_12567.vp.zip : 3 files : alpha.doc, beta.xls, teta.doc
I would like after extraction, files are renamed with the name of the zip
www_12567.vp.alpha.doc, www_12567.vp.beta.xls, www_12567.vp.teta.doc
Example 2 :
www_12.vp.zip : 3 files : al.doc, bea.xls, tta.doc
www_12.vp.al.doc, www_12.vp.bea.xls, www_12.vp.tta.doc
I found this question, but it talks about .txt and the zip contain one file, so, it doesn't work.
Without knowing the contents of the archive you can't know which files to rename, because you are putting them into a directory that may already contain other files.
This, however, would be much easier if there was a dedicated directory to put the files temporarily. Here's how you could use it:
#ECHO OFF
SET "srcdir=G:\toto"
SET "tgtdir=G:\toto\extracted"
SET "tmpdir=G:\toto\extracted-tmp"
FOR %%Z IN ("%srcdir%\*.zip") DO (
unpack "%%Z" with your favourite tool into "%tmpdir%"
FOR %%I IN ("%tmpdir%\*") DO MOVE "%%I" "%tgtdir%\%%~nZ.%%~nxI"
)
Of course, the temporary directory would need to be empty before running the batch file. You could add DEL "%tmpdir%\*" somewhere before the loop to make sure it is.
One other note is, the above assumes that the archives do not contain subdirectories or, at least, that the files are extracted without subdirectories.
UPDATE
If you are using the 7-Zip archiver to work with .zip files, then this is how your extract command might look:
7z e "%%Z" -o"%tmpdir%"
Disclaimer: I'm not an active user of 7-Zip. This is what I used as a reference to come up with the above command:
7-Zip Command-Line Examples
I have a script that changes particular string within files names (the file stores in "my_folder"):
Set objFso = CreateObject("Scripting.FileSystemObject")
Set Folder = objFSO.GetFolder("g:\my folder")
For Each File In Folder.Files
sNewFile = File.Name
sNewFile = Replace(sNewFile,"._epf","_v0_1._epf")
if (sNewFile<>File.Name) then
File.Move(File.ParentFolder+"\"+sNewFile)
end if
Next
the scrpit works fine if there are no folders under "g:\my folder", otherewise, if there are folders in "my folder" and the name of one (or more) of those folders are similiar to some file name, the scrip cause unwanted results like multiplying the replace string.
for example if "my folder" contain:
hello (folder)
hello_.epf (file)
then the script will eventually change the file name to:
hello_v0_1_v0_1._epf (unwanted result)
and i want the result to be:
hello_v0_1._epf
I'll appreciate quick help in this manner.
thanks.
I haven't bothered to try to figure out where your VBScript is going wrong. But you tagged your question with batch-file, batch, and batch-rename.
Here is a simple one-liner that can be run from the command prompt that will do what you want. It doesn't even need a batch script.
for %F in ("g:\my folder\*._epf") do #ren "%F" "%~nF_v0_1%~xF"
If you want to run the command within a batch script, then you need to double all percents.
#echo off
for %%F in ("g:\my folder\*._epf") do ren "%%F" "%%~nF_v0_1%%~xF"
EDIT
The above will append a new version suffix to each file name, before the extension.
If you want to replace an existing version number, then the solution is even easier. I'm assuming that your version always starts with _v, and v will never occur in the file extension.
ren "g:\my folder\*_v0_1._epf" "*v0_2.*"
The above command renames all files that end with _v0_1._epf. It preserves all characters up through the last occurance of v in the name, then adds the new version number, and finally appends the original extension.
See How does the Windows RENAME command interpret wildcards? for rules on how REN uses wildcards.
I am completely new to this, but I am trying to create a .bat file that will allow me to rename a pair of files within a designated folder and move them into a subfolder. The part I am having trouble with is that I am wanting a prompt to come up to identify/select the files to be renamed and moved.
Example file names are:
A1234, A1235, A1236, B1234, B1235, B1236, etc.
Is there a way to bring up a prompt that allows the user to type the shared name (ex 1234)of the files and rename and move both files to the designated subfolder?
Any and all help would be appreciated!
Suggested approach
for part of problem
part I am having trouble with is that I am wanting a prompt to come
up to identify/select the files to be renamed and moved. Is there a
way to bring up a prompt that allows the user to type the shared name
(ex 1234)of the files and rename and move both files to the designated
subfolder?
Do a search operation using wildcard, like "?1234" for the case highlighted above ( should be made generalized for all acceptable and expected patterns "*1234*" is the generic most )
Now do a RENAME inside a For loop on the results obtained by search.
As you suggest you are a newbie with Batch, following tutorials will help you build your file. Look for elements like Variables, For Loop
Batch Tutorial
Here you go
#echo off
set /p file=Please type shared name:
for %%a in (C:\Folder\?%file%.*) do (
move "%%a" subdir
ren "subdir\%%a" newname.*
)