i have a folder and it contains hundreds of text file, i want to rename it .
file names ABCD01%%.txt or CAT9999&#.txt OR FILENAME2345&^$.txt
i want to rename file such that anything that comes between 'numbers' and '.txt' should be removed
for example
ABCD01%%.txt becomes ABCD01.txt
CAT9999&#.txt becomes CAT9999.txt
FILENAME2345&^$.txt becomes FILENAME2345.txt
Code so far:
#echo off
for /f "tokens=*" %%f in ('dir /l /a-d /b *.txt') do (
for /f "tokens=1 delims=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" %%n in ("%%~nf") do (
echo File: %%~nxf = value %%n
rename %%~nxf *%%n.txt
)
)
Another solution i get for linux is rename 's/[^a-zA-Z0-9_]//g' *.txt , i tried to port it for windows but i cant .. how can the above command be ported to windows (batch)
Assuming there are no duplicate renames and assuming that only letters and numbers make up the first part of the filename, the following code will rename the files. When you are satisfied that the renaming is being done correctly, remove the -WhatIf from the Rename-Item command.
Get-ChildItem -File -Filter '*.txt' |
Where-Object { $_.Name -match '([A-Za-z0-9]*).*\.txt' } |
ForEach-Object { Rename-Item $_.FullName "$($matches[1]).txt" -WhatIf }
If you are not running in PowerShell, put the code into a renfunc.ps1 file and invoke it from the cmd .bat script.
powershell -NoProfile -File 'renfunc.ps1'
I've encountered a few problems with escaping characters, I had to use a slightly different method. This script should work:
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
set name=%%~nf
for /f "delims=0123456789 tokens=2" %%r in ("%%~nf") do set replace=%%r
set "replace=name:!replace:^^=!="
for /f %%x in ("!replace!") do set replace=!%%x!
ren "!name!.txt" "!replace!.txt"
)
EDIT: This revised script looks for the last numbers in the file name. [Don't mind the errors, they don't have any effect on the actual renaming.]
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
set name=%%~nf
set p=0
for /l %%# in (2 1 32) do (
for %%e in ("!name:~-%%#,1!") do (
echo.%%~e|findstr /r /i "[0-9]"&&if !p!==0 set /a p=%%#-1
)
)
set "new=name:~,-!p!"
for %%e in ("!name:~-1!") do echo.%%~e|findstr /r /i "^[0-9]"&&set new=name
for /f %%x in ("!new!") do ren "!name!.txt" "!%%~x!.txt"
)
EDIT: Revised again for the special case of "&&". Delayed expansion within a for-loop can be tedious. Now the characters won't break syntax anymore (which means the errors that were to be ignored have ceased).
Related
I have files such as:
How can I replace example to test-file in each of them?
I want solutions for:
Batch file
PowerShell
Bash
This is a batch-file solution:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%A IN ('dir /B /A-D "example*"') do (
set "fname=%%~nA"
rename "%%~fA" "!fname:example=test-file!%%~xA"
)
which should work. If you don't want to hardcode the word to replace, use:
#echo off
setlocal EnableDelayedExpansion
set "word=test-file"
for /F "delims=" %%A IN ('dir /B /A-D "example*"') do (
set "fname=%%~nA"
rename "%%~fA" "!fname:example=%word%!%%~xA"
)
For cmd one-line use:
for /F "delims=" %A IN ('dir /b /a-d "example*"') do #set "fname=%~nA"&call rename "%~fA" "%fname:example=test-file%%~xA"
Here's a batch-file solution:
#For %%A In (example*)Do #Set "_=%%A"&Call Ren "%%A" "test-file%%_:*example=%%"
As one has not yet been submitted, here's a powershell answer:
Get-ChildItem -Filter 'example*' | Rename-Item -NewName {$_.Name -Replace '^example','test-file'}
You could of course utilise PowerShell from a batch-file:
#Powershell -NoP "GCI -Filt 'example*'|RnI -N {$_.Name -Replace '^example','test-file'}"
For a bash solution, you're going to need to be more specific, because different OS'es/distributions etc. use different methods, some may use rename from util-Linux others may use the Perl rename utility. Others may not have rename and need to utilise a for loop with the mv command.
for f in example*; do mv "$f" "${f/example/test-file}"
[Edit /]
To run a command from the Command Prompt despite your lack of a cmd tag:
For %A In (example*)Do #Set "_=%A"&Call Ren "%A" "test-file%_:*example=%"
In bash you can use rename command like this:
rename example test-file example*
Here first argument is required expression to be changed, second argument is replacement and last argument is file name
I have around 180K files which needs to be move to folders based on the file name.
Files are with different extensions. I need to take all file names which start with numbers and get the number untill the first '-' and make a folder. Move all the files with the number in the folder.
Need to exclude files which do not start with numbers.
Sample Data: File Names
123-ACBDHDJ.pdf
123-dhdjd.txt
5658-dgdjdk.txt
456477-gse.docx
For example; Based on the above data mentioned on Filenames Above, I want to do the following:
make folders 123, 5658 and 456477
Move the first two files in folder 123, 3rd file in folder 5658 and
last file in folder 456477.
Tried below script:
#echo off
setlocal enabledelayedexpansion
for %%A in (*.psd *.jpg *.html *.tif *.xls *.xlsx *.htm *.csv *.pdf *.docx *.TXT *.zip *.msg *.xlsb *.eml *.*) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1* delims=-" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
pause
Issues currently facing:
Folders created with alpha numeric characters as well, I wanted to
ignore those files and pick only the ones starting with numbers.
Script running too long, very slow performance . Data volume is
very high, 180K records.
Please help with a batch script for this or any faster way to do this as the data volume is very huge. Thanks in advance.
Let's consider why it takes long. You have 128k files, you run 4 loops, meaning the for loops themselfs process each file 5 times, that is 640 000 processes on its own, you then run echos for each, that is even more processes, then we you check if a folder exists and if not create it, the folder exists is another process.. I guess you are getting where I am going with this. You are effectively running over a million procces to complete this task.
Maybe we get rid of all the unwanted for loops, use * instead of naming each file, then get rid of delayed expansion as we can simply get away without having to set variables:
#echo off
for %%i in (*) do (
echo file found %%i
for /f "tokens=1* delims=-" %%a in ("%%i") do (
if "%%a-%%b"=="%%i" (
md %%a>nul
move "%%~fi" %%a
)
)
)
echo Finished
pause
As for the name and extension part, you never use them after setting, If you still want to somewhere use the name and extension of the files, then you just use them without having to set vars:
#echo off
for %%i in (*) do (
echo file found %%i
for /f "tokens=1* delims=-" %%a in ("%%i") do (
if "%%a-%%b"=="%%i" (
md %%a>nul
move "%%~fi" %%a
echo This is the file extension: %%~xi
echo This is the filename: %%~na
echo This is the filename, drive and path: %%~dpi
echo This is the filename with full path: %%~fi
)
)
)
echo Finished
pause
You are using a lot of unnecessary code, which makes your batch file too slow. I would suggest something like:
#echo off
for %%A IN (*.*) do (
if not "%%~fA" == "%~f0" (
echo File found: %%A
for /f "tokens=1* delims=-" %%B IN ("%%~nxA") do (
md %%B>nul
(move "%%~fA" "%%~dpA%%B")>nul
)
)
)
echo Finished
pause
exit /b %errorlevel%
It seems also that the other loops you are making are useless. You can directly use %%~nA, %%~xA, e.t.c. See output of for /? in cmd.
You may already have an answer with the .bat file scripts. Here is a way to do it in PowerShell. When the script is tested and will move the files correctly, remove the -WhatIf from the Move-Item cmdlet.
$sourcedir = './s'
$destdir = './d'
Get-ChildItem -File -Path "$sourcedir/*" |
ForEach-Object {
if ($_.Name -match '^(\d+)-.*') {
$ddir = Join-Path $destdir $Matches[1]
if (-not (Test-Path -Path $ddir)) { New-Item -Name $ddir -ItemType Directory }
Move-Item -Path $_.FullName -Destination $ddir -WhatIf
}
}
This can be run from a cmd shell by saving the script into a file (thefile.ps1) and using the following command or putting the command into a .bat file script.
powershell -NoLogo -NoProfile -File thefile.ps1
I would do it the following way -- see all the explanatory remarks (rem) in the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=%~dp0." & rem /* (directory containing all the files; `%~dp0` points to the
rem parent directory of this batch script; to use the current
rem working directory, simply specify a single `.`) */
set "_MASK=?*-*.*" & rem /* (search pattern to find files, matching only files with at
rem least one hyphen in their names) */
set "_FILTER=^[0123456789][0123456789]*-" & rem /* (`findstr` filter expression;
rem this matches only files whose name begin with one or more
rem decimal digits followed by a hyphen) */
rem // Change to given root directory:
pushd "%_ROOT%" && (
rem // Loop through all matching files:
for /F "tokens=1* delims=-" %%E in ('
rem/ Return files and filter out those with non-numeric prefix: ^& ^
dir /B /A:-D "%_MASK%" ^| findstr /R /I /C:"%_FILTER%"
') do (
rem // Try to create target directory:
ECHO md "%%E" 2> nul
rem // Move file into target directory:
ECHO move /Y "%%E-%%F" "%%E\"
)
rem // Return from root directory:
popd
)
endlocal
exit /B
After having tested the script for correct output, remove both upper-case ECHO commands!
I used the below code in .bat file in order to delete all files and folders inside “AutoCAD_Temp” except “parcel.dwg” but it didn’t work with me.
#echo
set exclude=/Parcel.dwg/
for %%a in (C:\inetpub\Temp_FME\AutoCAD_Temp) do (
if "!exclude:/%%~a/=!" equ "%exclude%"
(
echo "Deleting" %%~a
del "%%~a"
)
)
The folder Path: C:\inetpub\Temp_FME\AutoCAD_Temp
enter image description here
What might be the issue here?
I will be very appreciated for any help,
Lubna
If there is only one file to protect, all you need to do is to lock it
#echo off
setlocal enableextensions disabledelayedexpansion
rem Just to avoid having to retype paths, place info on variables
set "folder=C:\inetpub\Temp_FME\AutoCAD_Temp"
set "excluded=Parcel.dwg"
rem If the excluded file exist, we will need to lock it.
if exist "%folder%\%excluded%" ( set lock= ^< "%excluded%" ) else ( set "lock=" )
rem Change to requested folder, remove anything not locked and return
pushd "%folder%" && (
rmdir . /s /q %lock% 2>nul
popd
)
The reason for the file existence check is to avoid trying to lock a non existing file that will make the command fail, so, lock variable (holding the part of the final command that will lock the file for reading) is only defined if the file exists.
This is one line in PowerShell, for your consideration:
Get-ChildItem C:\inetpub\Temp_FME\AutoCAD_Temp\* -File -Exclude Parcel.dwg | Remove-Item -WhatIf
(If the output is correct, remove the -WhatIf parameter to remove the files.)
use findstr to exclude the file from the search using /v
#echo off
for /f "delims=" %a in ('dir /b "C:\inetpub\Temp_FME\AutoCAD_Temp" ^| findstr /vi "Parcel.dwg"') do (
echo "Deleting" %%~a
echo del "%%~a"
)
if you would like to predefine variables, simply:
#echo off
set "mypath=C:\inetpub\Temp_FME\AutoCAD_Temp"
set "exclude=Parcel.dwg"
for /f "delims=" %a in ('dir /b "%mypath%" ^| findstr /vi "%exclude%"') do (
echo "Deleting" %%~a
echo del "%%~a"
)
What I'm trying to do is make a batch file that'll recursively go into every folder and count the number of files in each folder. However, I've spent the last hour trying various things and it isn't working.
I want the output to look like:
X:Y where X is the folder name and Y is the # of files in X.
setlocal EnableDelayedExpansion
set current=blank
FOR /D %%G in ("*") DO set current=%%G && call:count
:count
set count=0
for %%A in (*) do set /a count+=1
echo !current!:!count!>>"D:\User\Some\Directory\count.txt"
But this doesn't work. The output is giving the same number for each folder. The number it's outputting is the number of files in the directory itself, which I think is the problem.
Specifically, if I'm in C:\User\Example and it has three folders, A, B, and C, I want the number of files in C:\User\Example\A and so on, but it's giving me the number of files in C:\User\Example. Hope that makes sense.
Note: In my use case, the folders will not contain sub-directories.
A little different approach.
#echo off
FOR /D %%G in ("*") DO (
PUSHD "%%G"
FOR /F "delims=" %%H in ('dir /a-d /b * ^|find /C /V ""') DO echo %%G %%H>>"..\count.txt"
POPD
)
this works:
note that you have to collate set current=%%G&& call:count or current value is "A " (trailing space, not that you want)
And when you scan the subdir, you have to prefix * by your current dir
#echo off
del count.txt
setlocal EnableDelayedExpansion
set current=blank
FOR /D %%G in ("*") DO set current=%%G&& call:count
goto end
:count
set count=0
for %%A in (!current!\*) do set /a count+=1
echo !current!:!count!>>"count.txt"
:end
The answers to this question looks like a collection of different ways to do the same thing! Here it is another one:
#echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2 delims=\" %%a in ('findstr /M /S "^" *.*') do (
if "%%b" neq "" (
set "name=%%a"
set /A "count[!name: =_!]+=1"
)
)
(for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do (
set "name=%%a"
echo !name:_= !:%%b
)) > count.txt
This method look complicated because the management of spaces in the folders names. If folders don't have spaces, 6 lines (and Delayed Expansion) could be removed; that is:
#echo off
setlocal
for /F "tokens=1,2 delims=\" %%a in ('findstr /M /S "^" *.*') do (
if "%%b" neq "" set /A "count[%%a]+=1"
)
(for /F "tokens=2,3 delims=[]=" %%a in ('set count[') do echo %%a:%%b) > count.txt
Here is a PowerShell script to handle it:
Get-ChildItem -Path . -Recurse -ErrorAction SilentlyContinue -Force
| Where-Object { $_.Attributes -eq "Directory"}
| ForEach-Object {Write-Host $_.Name, $_.GetFiles().Count }
The prints to the screen, but writing to a file is simple.
The scans all the way down. If you just want the first layer of folders, remove the "-Recurse"
The advantage is that you are doing real actions on real objects, instead of trying to trick the OS into doing things it's not really intended for, by parsing text.
Here, it should be relatively simple to figure out what this is doing, even if you have little knowledge of PowerShell (Get a list of children, from this path, which are directories, and for each of them, print it's name, and the count of files in it.)
I need to rename a whole file structure, and find a certain piece of string such as "_foo" and rename it to "". The structure will be like :
something_foo->multiples_folders_and_files_foo->multiples_folders_and_files_foo->files_foo
Where all the files in each folders and each folders in each folders must not contain the piece fo string "_foo".
I am working under windows. I have tried powershell script, I was able to rename a single folder, but not recursivly rename all folders.
thanks guys!
#echo off
setlocal
set "string_to_remove=_foo"
set "root_dir=c:\root"
pushd "%root_dir%"
setlocal enableDelayedExpansion
for %%f in (*) do (
set "file_name=%%f"
ren "!file_name!" "!file_name:%string_to_remove%=!"
)
for /r /d %%# in (*) do (
set "dir_name=%%#"
pushd "%%#"
for %%f in (*) do (
set "file_name=%%f"
ren "!file_name!" "!file_name:%string_to_remove%=!"
)
popd
if "!dir_name!" NEQ "!dir_name:%string_to_remove%=!" move "!dir_name!" "!dir_name:%string_to_remove%=!"
)
popd
endlocal
Not tested but try this (in PowerShell)
PS> ls -rec -path $path | Ren -new { $_.name -replace '_foo' } -passthru
If work remove -passthru switch
Edit:
If '_foo' in the end of the name you can change the expression like:
| Ren -new { $_.basename -replace '_foo$' } -ea silentlycontinue
Edit:
For more robust code: (thank TheMadTechnician)
PS> GCI $path -filter '*_foo*' -rec | Ren -new { $_.name -replace '_foo' } -passthru
#echo off
setlocal enableextensions disabledelayedexpansion
set "remove=_foo"
for /f "delims=" %%a in ('dir /s /b "*%remove%*.*" 2^>nul ^| sort /r') do (
set "name=%%~nxa"
setlocal enabledelayedexpansion
for %%b in ("!name:%remove%=!") do endlocal & echo ren "%%~fa" "%%~b"
)
This will enumerate all matching files/folders, sort in reverse order (so files are processed before the folders that contains them) and for each one, remove the indicated string
Rename operations are only echoed to console. If the output is correct, remove the echo command