.bat Find and Replace text - batch-file

I have some files that contain some of if not all of the following:
Program RxBIN RXPCN RxGroup MemberID
not all files will have all of those headers but the ones that do I will need to replace so it looks like this:
#Program #RxBIN #RXPCN #RxGroup #MemberID
Thanks in Advance,
Joe

I'd still be inclined to go with a tool built for this purpose: Batch Replacer seems to fit the bill perfectly.
But if you're dead set on it... something using the old repl.bat with a multi arg parser... this becomes a bit of a monster that using the DEBUG command but here's the final masterpiece:
Source code: mmrepl.bat
#ECHO OFF
setLocal EnableDelayedExpansion
::: mmrepl - Replaces one or more strings with others, in file(s)
:::
::: syntax: mmrepl.bat $file $find $replace [$find $replace] ...
::: $file [in] - file to be parsed
::: $find [in] - string to find
::: $replace [in] - string to replace with
:::
::: * $find & $replace should be supplied in pairs, n multiples allowed
::: * $file can be a single file (eg.txt) or a file filter (*.txt)
::: you can supply any command that works with 'dir /b $file'
::: so paths and drives are also valid.
::: * $find,$replace strings can be single words, or strings enclosed
::: in quotes (which will be stripped)
if "%~1"=="" findstr "^:::" "%~f0"&GOTO:EOF
if not exist %1 echo No files matching %1 found&GOTO:EOF
::Creates the following log file:
set log=%0.log
::Temporarily creates the following files but cleans up
set replscr=TEMPDEBUG.SCR
set cmplsrc=TEMPEDLN.SCR
echo To see the work of %0.bat view the log file %log%
echo Multi-Multi Replacement (%0.bat)>%log%
echo.>>%log%
set "files=%1"
shift
set mmreplcmd=
:: Pair up find/replaces
:strippairs
set p1=%1
set p1=!p1:"=!
set p2=%2
set p2=!p2:"=!
SET mmreplcmd=%mmreplcmd%'1R%p1%' 1A '%p2%' 0D 0A
echo Replacing "%p1%" with "%p2%" >> %log%
shift
shift
if "%~1" neq "" goto:strippairs
::Build script
echo N%cmplsrc% > %replscr%
echo E CS:100 %mmreplcmd%'E' 0D 0A>> %replscr%
echo RCX >> %replscr%
echo 40 >> %replscr%
echo W >> %replscr%
echo Q >> %replscr%
DEBUG < %replscr% > NUL
::Execute on files
for /f %%a IN ('dir /b %files%') do (
echo.>>%log%
echo *** File: %%a >> %log%
EDLIN %%a < %cmplsrc% >> %log%
)
DEL %replscr%
DEL %cmplsrc%
NOTE: I had to remove the "is contained" within searching of repl.bat because you're adding an ampersand to each title so it's always containing... my testing shows this works fine, but YMMV (test).

This can be done trivially with sed (the stream editor) which is available for Windows in several places.
It could be done with something like
sed -e "s/\(Program\|RxBIN\|RXPCN\|RxGroup\|MemberID\)/#\1/g" myfile.txt > newfile.txt
This is a regular expression that basically says "substitute for the word 'Program' or 'RxBIN' or 'RXPCN' or 'RxGroup' or 'MemberID', an at-sign and whatever word was matched."
There are a lot of great Unix commands which have been ported to Windows that can be extremely helpful.

Related

Batch Echo Style: write two files at once [duplicate]

I am trying to use the tee code written for a bat file but am having trouble implementing it in my code. I don't want to use any third party installs to solve the tee problem as I want the code to work if I format my computer in a year and want to run the program again.
I have it setup in this fashion:
mycommand.exe | tee.bat -a output.txt
I've tried with a seperate .bat file and tried including as a function (preffered) in the original .bat to no avail with:
myprogram.exe | call tee -a output.txt
echo.
echo.
echo.
SET /P restart="Do you want to run again? (1=yes, 2=no): "
if "%restart%"=="1" GOTO LoopStart
::--------------------------------------------------------
::-- Function section starts below here
::--------------------------------------------------------
:tee
:: Check Windows version
IF NOT "%OS%"=="Windows_NT" GOTO Syntax
|
:: Keep variables local
SETLOCAL
:: Check command line arguments
SET Append=0
IF /I [%1]==[-a] (
SET Append=1
SHIFT
)
IF [%1]==[] GOTO Syntax
IF NOT [%2]==[] GOTO Syntax
:: Test for invalid wildcards
SET Counter=0
FOR /F %%A IN ('DIR /A /B %1 2^>NUL') DO CALL :Count "%%~fA"
IF %Counter% GTR 1 (
SET Counter=
GOTO Syntax
)
:: A valid filename seems to have been specified
SET File=%1
:: Check if a directory with the specified name exists
DIR /AD %File% >NUL 2>NUL
IF NOT ERRORLEVEL 1 (
SET File=
GOTO Syntax
)
:: Specify /Y switch for Windows 2000 / XP COPY command
SET Y=
VER | FIND "Windows NT" > NUL
IF ERRORLEVEL 1 SET Y=/Y
:: Flush existing file or create new one if -a wasn't specified
IF %Append%==0 (COPY %Y% NUL %File% > NUL 2>&1)
:: Actual TEE
FOR /F "tokens=1* delims=]" %%A IN ('FIND /N /V ""') DO (
> CON ECHO.%%B
>> %File% ECHO.%%B
)
:: Done
ENDLOCAL
GOTO:EOF
:Count
SET /A Counter += 1
SET File=%1
GOTO:EOF
:Syntax
ECHO.
ECHO Tee.bat, Version 2.11a for Windows NT 4 / 2000 / XP
ECHO Display text on screen and redirect it to a file simultaneously
ECHO.
IF NOT "%OS%"=="Windows_NT" ECHO Usage: some_command ¦ TEE.BAT [ -a ] filename
IF NOT "%OS%"=="Windows_NT" GOTO Skip
ECHO Usage: some_command ^| TEE.BAT [ -a ] filename
:Skip
ECHO.
ECHO Where: "some_command" is the command whose output should be redirected
ECHO "filename" is the file the output should be redirected to
ECHO -a appends the output of the command to the file,
ECHO rather than overwriting the file
ECHO.
ECHO Written by Rob van der Woude
ECHO http://www.robvanderwoude.com
ECHO Modified by Kees Couprie
ECHO http://kees.couprie.org
ECHO and Andrew Cameron
I am trying to split the output so I can save the console output to a file while still being able to interact with the program that is running.
How can I get the Tee command to work properly with my .bat so I can split the output to both a file and the console.
Your attempt to call a batch function within a pipe will always fail because of how Windows pipes work - Windows instantiates both sides of the pipe via new CMD shells. See https://stackoverflow.com/a/8194279/1012053 for more info.
That Rob van der Woude version of a batch tee cannot possibly work for you because it uses a FOR /F to read the results of a command - the command must execute to completion before any lines are read. That won't work if you need user interaction during the execution of the command. With that version of tee you might as well simply redirect output to a file and then TYPE the file when finished. Obviously not what you want.
There are pure batch tricks that can get you closer, but I think there is still one problem that can't be solved with pure batch. Your executable may put a prompt on a line without issuing a new line. I believe pure native batch always reads entire lines (except when at end of stream). I'm not aware of a batch method to read character by character.
Slight correction - SET /P can read partial lines of piped input, but it has limitations that prevent it from being used for a robust batch tee solution: There is no way to know for sure when each line ends. It is limited to 1021 characters per "line". It strips control characters from the end of each "line". There is no way to tell when it has reached the end of the input stream.
But there is a simple solution - JScript or VBScript works like a champ, and doesn't require any special installs. Here is a hybrid JScript/batch script that should work for you. The JScript is poorly written with lots of room for improvement. For example, there is no error checking.
I save the script as tee.bat. The first required argument specifies the name of the file to write to. By default, the file is over-written if it already exists. If a second argument is provided (value doesn't matter), then the output is appended to the file instead.
#if (#X)==(#Y) #end /* Harmless hybrid line that begins a JScript comment
::--- Batch section within JScript comment that calls the internal JScript ----
#echo off
cscript //E:JScript //nologo "%~f0" %*
exit /b
----- End of JScript comment, beginning of normal JScript ------------------*/
var fso = new ActiveXObject("Scripting.FileSystemObject");
var mode=2;
if (WScript.Arguments.Count()==2) {mode=8;}
var out = fso.OpenTextFile(WScript.Arguments(0),mode,true);
var chr;
while( !WScript.StdIn.AtEndOfStream ) {
chr=WScript.StdIn.Read(1);
WScript.StdOut.Write(chr);
out.Write(chr);
}
Usage is pretty much like you would expect.
command.exe | tee.bat output.txt 1
The last 1 argument forces append mode. It could be any value besides 1
It is possible to put everything in one batch script as you seem to prefer.
#if (#X)==(#Y) #end /* Harmless hybrid line that begins a JScript comment
::--- Batch section within JScript comment ----------------------------
#echo off
::This block of code handles the TEE by calling the internal JScript code
if "%~1"=="_TEE_" (
cscript //E:JScript //nologo "%~f0" %2 %3
exit /b
)
::The rest of your batch script goes here
::This pipes to TEE in append mode
mycommand.exe | "%~f0" _TEE_ output.txt 1
exit /b
----- End of JScript comment, beginning of normal JScript ------------------*/
var fso = new ActiveXObject("Scripting.FileSystemObject");
var mode=2;
if (WScript.Arguments.Count()==2) {mode=8;}
var out = fso.OpenTextFile(WScript.Arguments(0),mode,true);
var chr;
while( !WScript.StdIn.AtEndOfStream ) {
chr=WScript.StdIn.Read(1);
WScript.StdOut.Write(chr);
out.Write(chr);
}
Update
For anyone with an academic interest in batch scripting, I've posted a pure native batch version of tee at Asynchronous native batch tee script over at DosTips. But this hybrid approach is my preferred scripting solution.

Replace Special Characters In Batch-File Variable Feeding ffmpeg program

I am attempting to write a batch-file that leverages ffmpeg.exe to convert all files in a folder structure to mp3 format (specifically 128 KBps).
My batch-file is presently unable to process filenames (constructed by concatenating the %_SOURCE% and %%~F variables) containing certain special characters generating the following errors:
No such file or directory
… ellipsis sign
– en dash
— em dash
− minus sign
Invalid argument
‘ and ’ curved single quotation marks
“ and ” curved double quotation marks
Invalid argument (yet sometimes passes depending on where symbol is in the filename, for example, seems to work if placed between the n and t of Dont in C:\Users\Test\Documents\Input\Peter Bjorn And John - I Know You Dont Love Me.mp3)
- hyphen
! exclamation mark
~ tilde
' non-curved single quotation mark
= equals sign
+ plus sign
% percentage sign
( open bracket
How can I modify my batch-file script so that the %%~F variable escapes these characters correctly?
Example current filename input: C:\Users\Test\Documents\Input\Peter Bjorn And John - I Know You Don't Love Me.mp3
Example desired filename input: C:\Users\Test\Documents\Input\Peter Bjorn And John - I Know You Don"^'"t Love Me.mp3
Script (see line beginning C:\ffmpeg\bin\ffmpeg.exe):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=C:\Users\Test\Documents\Input" & rem // (absolute source path)
set "_TARGET=C:\Users\Test\Documents\Output" & rem // (absolute target path)
set "_PATTERN=*.*" & rem // (pure file pattern for input files)
set "_FILEEXT=.mp3" & rem // (pure file extension of output files)
pushd "%_TARGET%" || exit /B 1
for /F "delims=" %%F in ('
cd /D "%_SOURCE%" ^&^& ^(rem/ list but do not copy: ^
^& xcopy /L /S /Y /I ".\%_PATTERN%" "%_TARGET%" ^
^| find ".\" ^& rem/ remove summary line;
^)
') do (
2> nul mkdir "%%~dpF."
rem // Set up the correct `ffmpeg` command line here:
set "FFREPORT=file=C\:\\Users\\Test\\Documents\\Output\\ffreport-%%~F.log:level=32"
"C:\ffmpeg\bin\ffmpeg.exe" -report -n -i "%_SOURCE%\%%~F" -vn -c:a libmp3lame -b:a 128k "%%~dpnF%_FILEEXT%"
if not errorlevel 1 if exist "%%~dpnF%_FILEEXT%" del /f /q "%_SOURCE%\%%~F"
)
popd
endlocal
pause
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants:
set "_SOURCE=C:\Users\Test\Documents\Input" & rem // (absolute source path)
set "_TARGET=C:\Users\Test\Documents\Output" & rem // (absolute target path)
set "_PATTERN=*.*" & rem // (pure file pattern for input files)
set "_FILEEXT=.mp3" & rem // (pure file extension of output files)
pushd "%_TARGET%" || exit /B 1
for /r "%_SOURCE%" %%F in ("%_PATTERN%") do (
set "_fullpath=%%~F"
set "_filename=%%~nF"
call :ffmpeg
)
popd
endlocal
pause
exit /b
:ffmpeg
setlocal EnableDelayedExpansion
rem // Get target path and log path:
for %%A in ("!_fullpath:%_SOURCE%=.!") do (
set "_logpath=%%~dpAffreport-!_filename!.log"
set "_targetpath=%%~dpA"
)
for %%A in (_logpath _targetpath) do if not defined %%A (
echo ERROR: %%A not defined.
exit /b 1
)
rem // Escape logpath:
set "_logpath=!_logpath:\=\\!"
set "_logpath=!_logpath::=\:!"
set "_logpath=!_logpath:'=\'!"
set "_logpath=!_logpath:%%=%%%%!"
rem // Set FFREPORT:
set "FFREPORT=file=!_logpath!:level=32"
rem // Make dir for the target file:
if not exist "!_targetpath!" md "!_targetpath!"
rem // Run ffmpeg command:
"C:\ffmpeg\bin\ffmpeg.exe" -hide_banner -report -n -i "!_fullpath!" -vn -c:a libmp3lame -b:a 128k "!_targetpath!\!_filename!%_FILEEXT%"
if not errorlevel 1 if exist "!_targetpath!\!_filename!%_FILEEXT%" del /f /q "!_fullpath!"
exit /b 0
Use of for /f with a command tends to alter filenames if
contains Extended ASCII such as the ellipsis.
Using a for /r to iterate the files gives better results
and have adjusted the code to handle the change.
Added the label :ffmpeg to make it easier for working with
the delayed expansion variables etc.
Added _logpath variable to store the log filepath with any
backslash, colon or single quote to be escaped with a backslash.
Percent signs are escaped by doubling up.
Added _targetpath variable to store the path to where ffmpeg
is to output the file. Used by md command to make a directory
structure like that of the input.
This may not solve all issues. Tried to do without delayed
expansion though always had some failures depending on special
characters i.e. %.

findstr not working with string containing dash (-)?

I've been working on a BAT file which will delete old files based on creation date. To do this I've generated a list of all files and paths, then a list of files names to be protected. FINDSTR is then used to remove these files from the list of files and paths.
This system works fine until I encounter a file with a dash (or so it seems!)
Here's an example:
cleaner_protect.txt contains:
New File.txt
New File - Copy.txt
cleaner_fullpath.txt contains:
P:\New File.txt
P:\New File - Copy.txt
P:\Old File.txt
I want to remove the New Files stored in cleaner_protect.txt from the cleaner_fullpath.txt, leaving the Old Files behind which I will later delete (not up to that bit yet lol). Here is my code so far:
:: Remove protected files from list to be deleted (fullpath)
:RemoveFile
:: load string into variable
set /p target= <cleaner_protect.txt
:: remove protected file from full path list
echo -----------------------------
echo Searching for: "%target%"
echo -----------------------------
pause
findstr /v ".\<%target%\>." cleaner_fullpath.txt > cleaner_temp.txt
echo -----------------------------
type cleaner_temp.txt
echo -----------------------------
pause
del cleaner_fullpath.txt
ren cleaner_temp.txt cleaner_fullpath.txt
:: Count remaining lines in list
Set target=cleaner_protect.txt
Set /a lines=0
For /f %%j in ('Find "" /v /c ^< %target%') Do Set /a lines=%%j
Echo %target% has %lines% lines.
pause
:: Loop until completed
IF %lines% GTR 0 (
:: Remove line from protected list
more +1 cleaner_protect.txt > cleaner_temp.txt
del cleaner_protect.txt
ren cleaner_temp.txt cleaner_protect.txt
set /a lines-=1
GOTO :RemoveFile
)
Pauses and echos are for debugging purposes... I want this to run almost invisibly.
Can anyone shed some light on this? I need this code to repeatedly go through a dropbox and delete old files which may be in various levels of structure.
Maybe this simple line does all you want:
findstr /E /V /G:cleaner_protect.txt cleaner_fullpath.txt > cleaner_temp.txt
Sample output:
P:\Old File.txt
I would do it as follows:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem /* Prepend each line of `cleaner_protect.txt` with `\\`, remove a trailing space,
rem if applicable, and write result to `cleaner_temp.txt`: */
> "cleaner_temp.txt" (
for /F "usebackq delims= eol=|" %%E in ("cleaner_protect.txt") do (
set "ITEM=\\%%E|"
setlocal EnableDelayedExpansion
echo !ITEM: ^|=!
endlocal
)
)
rem /* Search `cleaner_fullpath.txt` for lines that do not end in any of the lines of
rem `cleaner_temp.txt` and process the returned items only: */
for /F "delims= eol=|" %%F in ('
findstr /V /I /E /L /G:"cleaner_temp.txt" "cleaner_fullpath.txt"
') do (
ECHO del "%%F"
)
rem // Clean up temporary file `cleaner_temp.txt`:
del "cleaner_temp.txt"
endlocal
exit /B
After having tested the script, remove the upper-case ECHO command.
Supposing cleaner_protect.txt contains this:
New File.txt
New File - Copy.txt
The temporary file cleaner_temp.txt is going to contain this:
\\New File.txt
\\New File - Copy.txt
So having the text file cleaner_fullpath.txt:
P:\New File.txt
P:\New File - Copy.txt
P:\Old File.txt
Only the following items are processed:
P:\Old File.txt
The leading \\ is taken as one literal \ by findstr (as it uses the \ as an escape character).
The prefix \\ is implemented in order to cover also the following situations:
Let us assume cleaner_protect.txt holds this:
New File.txt
And cleaner_fullpath.txt holds this:
P:\New File.txt
P:\Very New File.txt
Without the prefix, P:\Very New File.txt would also match New File.txt at the end, hence it would not become deleted erroneously.
Then let us assume cleaner_protect.txt holds this:
.File.txt
And cleaner_fullpath.txt holds this:
P:\.File.txt
P:\Other.File.txt
With a \ prefix, P:\Other.File.txt would also match \.File.txt at the end, because . is a meta character to findstr (even though literal search strings are defined by /L, but escaping like \. still applies and results in a literal .), hence it would also not become deleted erroneously. However, with a \\ prefix, escaping applies to the second \, so a literal \ is the result; the . does not need to be escaped with the /L option.

creating a batch file to copy pictures to a network drive

How do I create a batch file that will copy files from a camera to a directory that is prompted from the command line?
example folder structure: {shared drive start folder} <year> <month> <(prompt user for name)> [delete pictures after copied]
I am looking to get this to work to copy pictures from various cameras to one shared folder and have it all sorted by year then month and finally by the user prompted name. I know very little command line commands, all the switches and %'s.. i get lost pretty quickly.
Windows 7 computers and most likely SD cards in readers because most of the cameras don't show up with drive letters (this is part of my problem)
The code:
Show errors:
ECHO ON
type of file:
SET type=jpg
to set where the files are going:
NET USE M:\public\am_class\
to get user input i would use "SET /P" so i would do:
SET /P SDdrive=Enter Sd Card drive letter:
Get month and year(and day in case its needed later) to create initial folders:
FOR /F "TOKENS=1* DELIMS= "%%A IN ('DATE/T') DO SET CDATE=%%B
FOR /F "TOKENS=1,2 eol=/ DELIMS= "%%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/ "%%A IN ('echo %CDATE%') DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ "%%A IN ('echo %CDATE%') DO SET yyyy=%%B
SET date=%mm%%dd%%yyyy%
change dir to the correct location... this im not sure about but the "NET USE" gives me a direction to look in (figured out and placed correct code):
cd\
cd /DM:\public\am_class\"
make new folders in above main folder
mkdir "%yyyy%"
cd "%yyyy%"
mkdir "%mm%"
cd "%mm%"
!!next question is this correct to get it to create a folder from the user prompted info? (This is corrected and correct)
SET /P foldername=Please enter assignment number and press enter:
mkdir "%foldername%"
cd "%foldername%"
Go to SDdrive:
%SDdrive%
Find the Path of the files:
FOR /F "TOKENS=2 DELIMS\" %%A IN ('dir /b /s *.%type%') DO SET p1= %%A
Change folder and copy to "foldername" folder
CD"%p1%"
COPY *.* %foldername%
Delete the SDcard pics after complete:
Set /P delete=Delete SD card pictures (y/n)?
IF /I "%delete%"=="y" GOTO delY
IF /I "%delete%"=="y" GOTO delN
:delY
%SDdrive%
del /q *.*
explorer.exe \\landis.xxx\public\am_class\%foldername%\
:delN
explorer.exe \\landis.xxx\public\am_class\%foldername%\
Pause for testing only (will be removed in final version):
Pause
I hope that helps some.
Use the net use command to map the windows share to a drive like X:\ and then use
xcopy with some appropriate arguments to copy the files.
Like I said in my comment, your question is very broad with a lot of things to consider. I wrote a batch-file that I have used for years on many versions of Windows to download my pictures from SD cards. It does a good job, but it does not take into account that two different SD cards may have the same picture names on them -- even though they are different pictures. It simply skips pictures that have already been downloaded with the same filename in the destination folder.
I'm not going to write your code for you, nor do I have the time right now to help you navigate your way through learning the batch-file language, but I can at least post the two batch files that I use so that you can see some of the techniques that I used to accomplish what you're trying to do.
I created a shortcut in the SendTo folder that points to the DownloadPictures.bat so that when I insert an SD card into the card reader, I can send the images folder on the SD card to the shortcut and it downloads all of the pictures, separating them into folders based on the year/month/day they were taken. Then it opens each distinct destination folder using explorer.exe. The CMD window does not show anything during the download (i.e., nothing is echoed to the window), however, the title shows the overall progress and current image filesize (e.g., "1/300 7341254 bytes").
In order to grep the year, month and day from the file dates, I use another batch-file I wrote called SubStr.bat that lets me get a substring of the output of any DOS command and assign it to a variable. You must use Delayed Command Line Expansion for everything to work.
Please remember that this is not meant to be a solution for your question, but is simply an example that shows how to do some of what you are asking -- so that you can use it as a reference as you work on your own solution.
DownloadPictures.bat
#echo off
setlocal ENABLEDELAYEDEXPANSION
cd /d c:\
title Counting the files to download...
set _total=0
for /f "delims=" %%i in ('dir %1 /a-d /b /s') do set /a _total+=1
set _cnt=0
for /f "delims=" %%i in ('dir %1 /a-d /b /s') do (
set /a _cnt+=1
if /I "%%~xi" neq ".ctg" (
title !_cnt!/%_total%: %%i - %%~zi bytes
call substr "echo %%~ti" _date 0 n n "" sub 0 10
call substr "set _date" _year 0 n n "" end 4
call substr "set _date" _month 0 n n "" sub 6 2
call substr "set _date" _day 0 n n "" sub 9 2
set _dir=Q:\Photographs\Downloads\!_year!.!_month!.!_day!
md !_dir! > nul 2>&1
if not defined _old_dir set _old_dir=!_dir!
if "!_dir!" neq "!_old_dir!" (explorer !_dir!&set _old_dir=!_dir!)
if not exist !_dir!\%%~nxi copy %%i !_dir! > nul 2>&1
)
)
explorer !_dir!
echo All the pictures in directory %1 have been downloaded.
endlocal
SubStr.bat
#echo off
if "%7"=="" goto Help
:ExtractString
:: Remove the first and last " and convert all "" to ".
set __command_=%1
set __command_=%__command_:""="%
set __command_=%__command_:~0,-1%
set __command_=%__command_:~1%
:: Execute the command and direct the output to a unique file.
%__command_% > %TEMP%\_záfileáz_
:: Extract the specified line from the output file. (Note: You can't use 'skip'
:: with a value of '0'.) I used '«' as the delimiter because it is a character
:: that I will never encounter and this will ensure that I get the whole line
:: returned from the 'for' statement.
if "%3"=="0" (
for /f "delims=«" %%i in (%TEMP%\_záfileáz_) do if not defined _závaráz_ (set _závaráz_=%%i)
) else (
for /f "skip=%3 delims=«" %%i in (%TEMP%\_záfileáz_) do if not defined _závaráz_ (set _závaráz_=%%i)
)
if /i "%7"=="all" goto Finish
if /i "%7"=="sub" set _závaráz_=!_závaráz_:~%8,%9!
if /i "%7"=="end" set _závaráz_=!_závaráz_:~-%8!
:Finish
:: Kill spaces, quotes.
if /i "%4"=="y" set _závaráz_=%_závaráz_: =%
if /i "%5"=="y" set _závaráz_=%_závaráz_:"=%
:: Remove unwanted characters (pad the front with an unlikely string so that the
:: FOR statement will never complain because of an empty set). The %%~i notation
:: strips quotes out of the string and spaces are delimiters. This is why they
:: each (spaces and quotes) have their own parameters above...
set __remove_=%6
set __remove_=ßa¯¦¯aß %__remove_:~1%
set __remove_=%__remove_:~0,-1%
set __remove_=%__remove_:""="%
for %%i in (%__remove_%) do set _závaráz_=!_závaráz_:%%~i=!
:: Set the output variable.
set %2=!_závaráz_!
:Cleanup
set _závaráz_=
del %TEMP%\_záfileáz_
set __command_=
set __remove_=
goto TheEnd
:Help
echo.
echo SubStr
echo ================================================================================
echo.
echo Syntax:
echo.
echo SubStr ["command"] [output variable] [Lines to Skip] [Remove Spaces]
echo [Remove Quotes] [Remove Other] [action [var1] [var2]]
echo.
echo Parameters:
echo.
echo Command - The command that creates the output characters. If the
echo command includes calling another batch file, issue the
echo command by using the 'call' function
echo (e.g., "call another.bat"). When your command is passed,
echo it must be enclosed in quotes. If part of the command needs
echo to also have quotes (i.e., for long filenames), the strings
echo within the command that need to be quoted need to be double
echo quoted (e.g., "dir ""c:\win 2000\notepad.exe"" /x"). When
echo the command is executed, the initial and final quotes will
echo be stripped off and all sets of double quotes ("") will be
echo replaced with single quotes (").
echo.
echo Output Variable - The name of the variable to use (set var=copied text).
echo.
echo Lines to Skip - The number of lines before the line from which you want to
echo copy text.
echo.
echo Remove Spaces - Removes spaces out of the copied text.
echo.
echo Remove Quotes - Removes quotes from the copied text.
echo.
echo Remove Other - A string of strings that should be removed from the copied
echo text. The set of strings or characters must be enclosed in
echo a single set of double quotes. At times, some characters
echo may not be elimated (e.g., a comma) unless it too is
echo enclosed in quotes. To do this, the quotes must be doubled.
echo For example: "a b c d "","" e f h"
echo.
echo Action - Action to perform:
echo All - Copies entire string.
echo Sub - Extracts part of the string where var1 is the
echo starting position and var2 is the number of
echo characters to copy. var1 is zero based. A negative
echo value for var2 omits the specified number of
echo characters from the end of the string.
echo End - Only extracts the specified number of characters
echo from the end of the string (specified by var1).
echo.
echo Example:
echo.
echo SubStr "dir c:\windows\system32\notepad.exe /-c" _filesize 5 y n "" sub 20 18
echo.
echo This command assigns the size of notepad.exe to the variable _filesize.
echo Try running it and then type 'set _' at the command prompt.
echo.
echo Notes:
echo.
echo Make sure delayed command line expansion is enabled in the calling batch file
echo via the "setlocal ENABLEDELAYEDEXPANSION" command, or enable it globally by
echo editing the registry as follows (and then reopen your CMD windows):
echo.
echo Location: HKEY_CURRENT_USER\Software\Microsoft\Command Processor
echo Item: DelayedExpansion
echo Type: dword
echo Value: 1
echo.
echo ================================================================================
echo.
:TheEnd
Thank you James L and User.
James:
Post 1: I though about asking some one to do it for me but then I would never learn anything from it. ignoring your telling me to the the towel in i got a working program.
Post 2: Very very useful post. Not only did it have code (i got to work no problem) you gave a description of how you used it. the first code is going to take me a while to decode what is what and how you did it. The second code it VERY HELPFUL, its well documented and i understand more of whats going on it it.
User:
This ended up being what i used to get my program to work. I had to keep it simple :)
Thank you both for your help with this posted problem.
James: thank you very much for all the code and useful information that your second post was teeming with.
This is the final working code for copying pictures from an SD card to a specific user named folder sorted by year then month then project name. This is set for the SD Drive to be drive letter "F:" you can change it to what you need or delete "#SET cameradrive=F:" and remove the "REM" from the line above and it will prompt the user for the drive letter. It takes the user input and makes it all capitals to make a cleaner looking folder. One thing to note: this doesn't work if the folder name has a space in it. I have to figure out how to fix that (ill be posting a question on it here). It then opens the folder in explorer so you can verify that everything went OK. After you have checked then you can delete the files on the SD card by pressing "y" and hitting enter. If you don't want to delete them then press "n" and hit enter. This copies EVERY PICTURE on the SD card in the nested folder so if you have multiple photos you want to go different places this wont work for you. also if your pictures aren't jpg then just change the "SET type=" to what ever your file type is. I placed a program called "USB Ejector" into the root of the SD card so that when the batch file is completed it automatically safely removes the card from windows.
# echo on
# SET type=jpg
# SET userfolder=C:
#cd /dy:\landis\public\am_class
#REM SET /P cameradrive=Enter Camera Drive Letter (ie D:) and hit Enter:
#SET cameradrive=F:
set /p foldername=Type Folder name and hit Enter:
#REM This makes everything uppercase.
# SETLOCAL ENABLEDELAYEDEXPANSION
# SET _SAMPLE="%foldername%"
# CALL :UCase _SAMPLE _RESULTS
# ECHO.%_RESULTS%
# CALL :LCase _SAMPLE _RESULTS
# ECHO.%_RESULTS%
# ENDLOCAL
# GOTO:EOF
# :LCase
# :UCase
# :: Converts to upper/lower case variable contents
# :: Syntax: CALL :UCase _VAR1 _VAR2
# :: Syntax: CALL :LCase _VAR1 _VAR2
# :: _VAR1 = Variable NAME whose VALUE is to be converted to upper/lower case
# :: _VAR2 = NAME of variable to hold the converted value
# :: Note: Use variable NAMES in the CALL, not values (pass "by reference")
# SET _UCase=A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
# SET _LCase=a b c d e f g h i j k l m n o p q r s t u v w x y z
# SET _Lib_UCase_Tmp=!%1!
# IF /I "%0"==":UCase" SET _Abet=%_UCase%
# IF /I "%0"==":LCase" SET _Abet=%_LCase%
# FOR %%Z IN (%_Abet%) DO SET _Lib_UCase_Tmp=!_Lib_UCase_Tmp:%%Z=%%Z!
# SET %2=%_Lib_UCase_Tmp%
#REM GOTO:EOF
#REM
# SET foldername=%_RESULTS%
#REM SETTING THE YEAR AND MONTH VARIABLES
# SET yyyy=%date:~10,4%
# SET mm=%date:~4,2%
#REM CREATING THE FOLDERS WITH THE NAMES AND NESTING THEM CORRECTLY
# mkdir %yyyy%
# cd %yyyy%
# mkdir "MSU Orders"
# cd "MSU Orders"
# mkdir %mm%
# cd %mm%
# mkdir "%foldername%"
# cd "%foldername%"
#REM COPY THE CONTENTS OF THE CAMREA PIC FOLDER TO THE NEW FOLDER
# xcopy /e /v %cameradrive%\DCIM\100NIKON "\\landis\public\am_class\%yyyy%\%mm%\%foldername%\"
# explorer.exe \\landis\public\am_class\%yyyy%\%mm%\%foldername%\
#REM Delete the originals prompt and then actions
# SET /P delete=Delete Original Photos from Camera (y/n)?
# IF /I %delete%==y GOTO :dely
# IF /I %delete%==n GOTO :deln
# GOTO :deln
# :dely
# cd /d%cameradrive%\DCIM\100NIKON
# del /q *.*
# GOTO :done
# :deln
# GOTO :done
# :done
# cd /dc:\
# F:\USB_Disk_Eject.exe /removethis
# pause

How to write a single spacebar to a txt file with batch

I need to add a single spacebar to a textfile ussing batch
however the following dosnt work
ECHO >C:\txt.txt
this produces the text Echo is (off) instead???
Im ussing windows batch
echo is printing the text "ECHO if off" because you haven't provided any parameters to it. If you type echo /? for usage instructions you will see this behavior defined: "Type ECHO without parameters to display the current echo setting". So, in your case, echo is set to off.
If you want to have on the space character without a newline and carriage return you will most likely need to use set. If you are using Windows XP, this should be easy.
Windows XP
>txt.txt ( <nul set /p "= " )
If you are running Vista or Higher it keeps a little tricky because windows strips leading spaces on the set command.
Windows Vista or Higher
You will need to create a backspace character and then print that:
:: Create a backspace character
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
<nul set /p=%BS% > txt.txt
Note that this doesn't actually print a space, but a backspace character instead. I'm not quite sure if this will work for you, but I couldn't think of any easier way. Otherwise you are probably better off using some other scripting language, like python or powershell.
Echo a space (+ line break)
ECHO. > C:\txt.txt
Note that this will output a carriage return plus line break (an enter) as well. So your file will become 3 bytes.
Alternatively, you may create the file with a 0-byte using
fsutil file createnew c:\txt.txt 1
Only this doesn't add a space, but a 0 character.
Alternatively, you may create a file with a single space once, and copy that to txt.txt each time you need it to contain a space.
Use an external tool, like echon.exe from this zipfile (from this site). It mimics echo -n, like it is available in Linux.
To create a single space with Win Vista or above you can't use the SET/P command anymore (as dbenham mentioned).
But you can use the copy command
#echo off
setlocal EnableDelayedExpansion
call :createSub
call :echoWithoutLinefeed "=hello"
call :echoWithoutLinefeed " world"
exit /b
:echoWithoutLinefeed
> txt.tmp (echo(%~1!sub!)
copy txt.tmp /a txt2.tmp /b > nul
type txt2.tmp
del txt.tmp txt2.tmp
exit /b
:createSub
copy nul sub.tmp /a > nul
for /F %%a in (sub.tmp) DO (
set "sub=%%a"
)
del sub.tmp
exit /b
First the text is outputs with a simple ECHO but at the end a SUB character is appended, just before the ECHO appends CR LF.
And with copy inputfile /a outputfile /b all characters are copied up to the first SUB character.
Not only does SET /P not print leading white space on Vista and beyond, it also cannot print leading =.
Below is code that works on all modern versions of Windows from XP onward:
#echo off
setlocal enableDelayedExpansion
for /f %%A in ('copy /Z "%~dpf0" nul') do set EOL=%%A^
:: The above two empty lines are critical - DO NOT REMOVE
<nul set /p "=x!EOL! " >temp.tmp
findstr /v $ temp.tmp >file.txt
del temp.tmp
The above technique can be extended to support printing nearly any string without newline, with a few exceptions:
The string must not contain a carriage return
XP FINDSTR will display most control characters and many extended ASCII characters as dots. See What are the undocumented features and limitations of the Windows FINDSTR command? for more info.
Here are two methods for 32 bit Windows:
This method creates a file directly with hex 20 (space):
#echo off
(for %%v in (E100''20 Nfile.tmp RCX 01 W Q) do #echo %%v)|debug >nul
ren file.tmp "file with a single space.txt"
This one removes the two trailing characters from the file.tmp file
#echo off
set f=file.tmp
echo. >%f%
(for %%v in (E100''83''E9''02 L103 P N%f% W103 Q) do echo %%v)|debug %f% >nul
ren %f% "file with a single space.txt"
This will work on Vista and higher, any bitness.
#echo off
(
echo -----BEGIN CERTIFICATE-----
echo IA==
echo -----END CERTIFICATE-----
)>file.tmp
certutil -decode file.tmp "file with a single space.txt" >nul
del file.tmp
Here is the way to create a one byte single space file without creating a temporary file.
cmd /d /c (prompt=$S) ^& cmd /d /k <nul >SingleSpace.txt

Resources