Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 8 years ago.
Improve this question
We are in the process of moving to OneDrive for Business. To store files in OneDrive you can't have the following charactes in the filename:
/:*?"<>|#%
Additionally, a file name that begins with a tilde (~) isn't supported.
I would like to search and replace the special character with a dash.
Anyone have a batch file or powershell script?
Coincidentally, \ / : * ? " < > | aren't allowed in Windows filenames either, so most of your list is already a non-issue. Assuming that list of characters is complete, all that remain are hashes, percents, and leading tildes.
#echo off
setlocal
:: replace ~ only if first char of filename
for %%I in ("~*") do (
set "file=%%~I"
setlocal enabledelayedexpansion
echo %%~I -^> -!file:~1!
ren "%%~I" "-!file:~1!"
endlocal
)
:: replace # or % everywhere in filename
for %%d in (# %%) do (
for %%I in ("*%%d*") do (
set "file=%%~I"
setlocal enabledelayedexpansion
echo %%~I -^> !file:%%d=-!
ren "%%~I" "!file:%%d=-!"
endlocal
)
)
But as Dour points out, this only fixes some of the problems. Your file uploads might still require some hand-holding. Or who knows? This could solve all your worldly problems. shrug
Edit: O.P. asked about adding /r to the for loops to make the replacements recursive. You could do that with a few tweaks, but you'll end up looping through the file list 3 times -- once for each symbol you're replacing. I suggest this would be a more efficient approach:
#echo off
setlocal enabledelayedexpansion
if "%~1"=="" goto usage
if not exist "%~1" goto usage
pushd "%~1"
for /r %%I in (*) do (
set "file=%%~nxI"
if "!file:~0,1!"=="~" (
set "file=-!file:~1!"
)
for %%d in (# %%) do (
if not "!file!"=="!file:%%d=!" (
set "file=!file:%%d=-!"
)
)
if not "!file!"=="%%~nxI" (
echo %%~fI -^> !file!
ren "%%~fI" "!file!"
)
)
goto :EOF
:usage
echo Usage: %~nx0 pathname
echo To operate on the current directory, use a dot as the pathname.
echo Example: %~nx0 .
Edit 2: Added argument syntax.
Related
I have a directory with files of kind *.aaa that I want to convert to kind *.bbb (using the exact same file name, only the file format changes) with a batch script in Windows command prompt.
Since there are many files in the directory, I don't want to do unnecessary conversion, so it should only be done if file.bbb does not exist, or if file.aaa is newer than the current file.bbb
I am quite a beginner when using batch scripts, but after doing some searching on how to compare the time that files were modified, I came up with the following my_convert.bat file:
FOR %%i IN (*.aaa) DO (
REM Check if *.bbb already exists
IF EXIST "%%~ni.bbb" (
REM if *.bbb already exists, check if it is up to date
FOR /f %%j IN ('dir "%%~ni.*" /b/a-d/od/t') DO SET LATEST=%%j
ECHO The most recently modified file is %LATEST%
IF %LATEST:~-3% == "aaa" (
REM *.bbb is out of date, do my conversion here
)
) ELSE (
REM *.bbb does not exist, do my conversion here
)
)
However, this does not work. It loops through all the files in my directory, but always displays that the last file in the directory is the 'most recently modified file'. I am clearly not understanding something about my implemented logic right. Any help to steer me in the right direction will be much appreciated.
jbdv, I summarize your comments into an answer mainly to get this question from list of unanswered questions, but adding also some additional information about difference between environment variables and FOR variables.
The final working code used is:
SETLOCAL EnableDelayedExpansion
FOR %%i IN (*.aaa) DO (
REM Check if *.bbb already exists
SET BASENAME=%%~ni
IF EXIST "!BASENAME!.bbb" (
REM if *.bbb already exists, check if it is up to date
FOR /f %%j IN ('dir "!BASENAME!.*" /B /A-D /OD /T') DO SET LATEST=%%j
ECHO The most recently modified file is !LATEST!
IF !LATEST:~-3! == "aaa" (
REM *.bbb is out of date, do my conversion here
)
) ELSE (
REM *.bbb does not exist, do my conversion here
)
)
ENDLOCAL
Well, the replacement of %%~ni by environment variable BASENAME would not be necessary as code below demonstrates.
SETLOCAL EnableDelayedExpansion
FOR %%i IN (*.aaa) DO (
REM Check if *.bbb already exists
IF EXIST "%%~ni.bbb" (
REM if *.bbb already exists, check if it is up to date
FOR /f %%j IN ('dir "%%~ni.*" /B /A-D /OD /T') DO SET LATEST=%%j
ECHO The most recently modified file is !LATEST!
IF !LATEST:~-3! == "aaa" (
REM *.bbb is out of date, do my conversion here
)
) ELSE (
REM *.bbb does not exist, do my conversion here
)
)
ENDLOCAL
The FOR variables i and j are not environment variables. Therefore %%i and %%j with or without a modifier like ~n are never replaced by a string on parsing a block before execution.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
PUSHD "%sourcedir%"
FOR /f "delims=" %%a IN (
'dir /b /a-d *.aaa '
) DO (
FOR /f "delims=" %%b IN (
'dir /b /od /a-d "%%~na.aaa" "%%~na.bbb"'
) DO SET "convert=%%~xb"
IF /i "!convert!" NEQ ".bbb" ECHO(CONVERT "%%~na"
)
POPD
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
With each .aaa file, list the .aaa (which must exist - we've just checked that) and the .bbb file for the name part %%~na in date-order (/od) so that the last extension in the list will be .bbb only if it both exists and is later than the .aaa file. Otherwise, do the conversion - the convert command and file name will be shown on the console. You could convert "%%~na.aaa" if you need the full name.
first of all im beginner. i want to create batch file to search through specific folder (including all it subfolder) and copy all file inside it except those which filename contain some specific string,this is what i have so far
set now=fish
set logDirectory="C:\Users\paiseha\Desktop\bb\"
for /r %logDirectory% %%i IN (*%now%*.*) do (
rem copy process goes here
)
let say i have 3 file in it
C:\Users\fareast\Desktop\bb\one.txt
C:\Users\fareast\Desktop\bb\twofishtwo.txt
C:\Users\fareast\Desktop\bb\three.txt
so i want to copy file one.txt and three.txt only, but instead it copy only the second one,i know its because of *%now%*.* so how can i invert it so that it does the other way around, help me pls, thanks in advance
try:
#ECHO OFF &setlocal
set "now=fish"
set "logDirectory=C:\Users\paiseha\Desktop\bb"
for /f "delims=" %%a in ('dir /a-d/b/s "%logDirectory%"^|findstr /riv "^.*[\\][^\\]*%now%[^\\]*$"') do (
rem copy process goes here
)
EDIT: The \ character is represented as [\\] instead of \\ because of a quirk on how Vista FINDSTR regex escapes \. Vista requires \\\\, but XP and Win 7 use \\. The only representation that works on all platforms is [\\]. See What are the undocumented features and limitations of the Windows FINDSTR command? for more info.
for /f "delims=" %%a in ('dir /a-d/s/b "%logDirectory%" ') do echo %%~nxa|findstr /i /L "%now%" >nul&if errorlevel 1 ECHO COPY "%%a"
should work for you.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 9 years ago.
Improve this question
I want to create a bat file that copies all jpeg image files created on a specific date - eg 2013/05/05.
It will go something like this:
xcopy g:\DCIM\images\'command for date'*.jpg c:\users\david\images\newImages
How do I accomplish that?
I tried the following but it copied all the images in the folder and ignore the date param:
xcopy /l /s /d:05-05-2013 g:\DCIM\images\*.jpg c:\users\david\images\newImages
Try this:
#echo off
setlocal
for /f "tokens=1,5 delims= " %%a in ('dir /a-d /tc G:\DCIM\images\*.jpg') do (
if %%a equ 2013/05/05 copy "g:\DCIM\images\%%b" "c:\users\david\images\newImages"
)
try this:
#echo off&setlocal
cd /d "g:\DCIM\images"
for /f "tokens=3" %%i in ('dir ^|findstr "^[0-9]"') do set "AMPM=%%i"
if "%AMPM:M=%"=="%AMPM%" (set "AMPM=3") else set "AMPM=4"
for /f "tokens=1,%AMPM%*" %%i in ('dir /a-d /tc *.jpg') do if "05-05-2013"=="%%i" echo copy "%%k" "c:\users\david\images\newImages"
I know there are questions here like this before but in my case there are special conditions in specifying the files to be excluded in the "delete" operation.
Filename examples:
A_001.xml
A_002.xml
B_001.xml
B_002.xml
B_003.xml
C_009.xml
D_002.xml
The files above are in one directory and I need to delete all files but retain one copy of each file with the highest counter in filename which are A_002.xm, B_003.xml, C_009.xml and D_002.xml.
Is this possible? I'm new in batch file creation so please help me.. I already know how to delete files and even exclude a specific file extension but I don't know what to do in this scenario.
#ECHO OFF
SETLOCAL enabledelayedexpansion
::
:: establish target directory
:: initialise PREFIX to a name that's invalid in a filename
::
SET target=.
SET prefix=:
FOR /f "tokens=1*delims=_" %%i IN (
'dir /b/a-d/o-n "%target%\*_*.xml'
) DO (
IF !prefix!==%%i ECHO DEL "%target%\%%i_%%j"
SET prefix=%%i
)
This solution relies on the presence of "_" in the names of the *xml files in the target directory. I tested it on some dummy files in my batch-development directory, hence I used . for the current directory
The DIR command produces a list of the files in the target directory that match the pattern *_*.xml The/b switch means filename only, /a-d means no directory names, even if they match and /o-n means in the reverse order of name Therefore, the names will appear with the highest numeric value of the part after _ first.
The FOR reads this output and assigns the prefix to %%i and the remainder of the filename to %%j Since prefix is initialised to an invalid-in-filenames character, it cannot possibly match %%i for the first file encountered, so the DEL will not be executed. The last-encountered prefix will then be stored. Only if the next filename has a matching prefix will the DEL be executed
Note that I've inserted the ECHO keyword before the DEL. This is a safety device in case of error. The PROPOSED DEL operation will be reported to the screen, not EXECUTED. Once you're satisfied that the batch is correct, remove the ECHO and the delete operation will proceed.
Point to be observed:
Some editors are quite cavalier about stripping or retaining trailing
spaces. Normally, this is harmless but trailing spaces on a SET
command in batch can cause chaos.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set newprefix=_
for /F %%a in ('dir /on /b /a-d *.xml') do (
for /F "delims=_" %%i in ("%%a") do (
IF NOT *%%i*==*!newprefix!* (
for /F %%q in ('dir /on /b /a-d %%i*.xml') do set lastitem=%%q
attrib +r !lastitem! > NUL
del /s /q %%i*.xml 1>NUL 2>NUL
attrib -r !lastitem! > NUL
set newprefix=%%i
)
)
)
For each prefix of xml file, lists all the files with the prefix in question to get the last one in the list. Then mark the last one read only. Delete all with given pattern except read only. Reset read only flag and do over for next prefix.
I run this code on Windows cmd.exe in Europe and I use local settings here, for my language. So I use diacritics in names of the directories.
I try to list names of the directories and they are displayed correctly. Then I save them into file, but when I open it in notepad, the diacritics is not readable: for example, instead of Střední Čechy I have Stýednˇ ¬echy.
What did I do wrong and how can I correct it?
#echo off
del directories.conf
FOR /F "delims=!" %%R IN ('dir * /b /a:d /o:n') DO (
IF EXIST "%%R\scenery" (
echo %%R
echo %%R >> directories.conf
) ELSE (ECHO NOT INCLUDED %%R)
)
Echo Directory list created...
pause
Try starting cmd.exe with /u switch. That will cause cmd to write in UTF-16.
Also you need to switch to code page 1250 (ANSI for Central Europe) using chcp 1250.
You can do it inside your batch script. I made one for you. The structure is:
.\Jižní Morava
.\Jižní Morava\scenery
.\Pelhřimov
.\Pelhřimov\scenery
.\Nic moc výlet
.\Střední Čechy
.\Střední Čechy\scenery
And the script:
#echo off
if _%1_==_main_ (
call :main
) else (
cmd /u /c "%0 main"
)
goto :eof
:main
chcp 1250
del directories.conf
for /F "delims=!" %%R in ('dir * /b /a:d /o:n') do (
if exist %%R\scenery (
echo %%R
echo %%R >> directories.conf
) else (
echo not included: %%R
)
)
echo Directory list created...
pause
goto :eof
Also I recommend you to read andrewdotn's great answer to a related question.
As an alternative solution (if the file is already generated) you can just re-encode your file.
Notepad++ has this feature:
Go to Encoding > Character sets
Select the appropriate character set that has a graceful render
Go back to Encoding > Character sets
Select Convert to UTF-8
Save your file