I have a script on which the last line echos out the last line of a text file (minus the first 7 characters) to another file:
for /f "delims==" %%a in (c:\file1.txt) do set lastline=%%a
echo(%lastline:~7%> file2.txt
The lines look like this (I'm grabbing the name only with the above code):
4.53 - Billy
2.63 - Mark
12.42 - Tom
The problem is that if the last line starts with a two digit number before the decimal. The echo still works but the output includes the SPACE in between the - and the name because it is skipping 7 characters. I have to cater for both.
Is there a way to echo without including leading SPACEs? Or can I add a line afterwards which can remove all white-spaces from file2.txt?
I would not try to remove the leading SPACE, I would change the method of removing the number. Apply this to remove everything up to and including SPACE-SPACE:
echo(%lastline:* - =%> file2.txt
Or the better syntax:
> file2.txt echo(%lastline:* - =%
The latter variant is better in order to avoid trouble when the last character of the string to echo is a single numeral, separated from the rest by a token delimiter, because, together with the > symbol, it constitutes a redirection operator, like 2>, for example.
Just for the sake of completeness, to remove leading white-spaces, use this:
for /F "tokens=*" %%L in ("%STRING%") do echo(%%L
This works, because the default delimiters of for /F are SPACE and TAB.
Related
I have a variable that contains the following:
"pdfList=D:\BundleManager\AssetPackageManager.unity;D:\BundleManager\AssetPackageManager.unity\.vs\AssetPackageManager.unity;D:\Crafting\CraftingExample.unity;D:\ResMan\FFResManExample.Unity;"
And I want to call a function for each of those paths separated by ; The code I currently have is
for /F "delims=;" %%a in ("%pdfList%") do (#echo %%a)
But this is just echoing the following
D:\BundleManager\AssetPackageManager.unity
I've tried setting tokens=* as an option but this just echos the value of pdfList complete with ; still present. Where am I going wrong?
The problem with your code is that for /F loops line-by-line, rather than token-by-token. A better solution is to use for without any switches. for will tokenize data, splitting on unquoted spaces, commas, semicolons, and tabs.
To prevent pathnames containing spaces or commas from being truncated, you can massage the data and replace all semicolons with ";" using batch variable substring substitution, then surround the whole thing in quotation marks. See this page for full details on substring replacements.
So basically,
a;b c;d e;f
becomes
a";"b c";"d e";"f
becomes
"a";"b c";"d e";"f"
which is easily tokenized, and spaces are preserved. Apply this principle to your code above:
#echo off & setlocal
set "pdfList=D:\BundleManager\AssetPackageManager.unity;D:\BundleManager\AssetPackageManager.unity\.vs\AssetPackageManager.unity;D:\Crafting\CraftingExample.unity;D:\ResMan\FFResManExample.Unity"
for %%a in ("%pdfList:;=";"%") do echo(%%~a
The output is now:
D:\BundleManager\AssetPackageManager.unity
D:\BundleManager\AssetPackageManager.unity.vs\AssetPackageManager.unity
D:\Crafting\CraftingExample.unity
D:\ResMan\FFResManExample.Unity
Remove trailing spaces from a file using Windows batch? and How to remove trailing and leading whitespace for user-provided input in a batch file? seem to be similar questions, but I can't get any of the answers to work.
I have a text file, say C:\Users\%username%\Desktop\sometext.txt that has a long list of numbers, some with trailing whitespace. How can I loop through and remove the whitespace at the end of each line? I'd like to do this all in batch. It'll be in a file with some other batch commands in it.
Regrettably, you don't show us an example from your file, so we're left to assume from your desription.
Assuming your file is something like
1
22
3
64
where some of the lines have trailing spaces, then
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /f "usebackq" %%a IN (q30594509.txt) DO (
SET /a num=%%a
ECHO(!num!
)
)>u:\newfile.txt
GOTO :EOF
I used a file named q30594509.txt containing the above data for my testing.
Produces u:\newfile.txt
I have a text file with n number of rows. m number of the rows contain a string that I'm interested in (m<=n). I need a batch file that will copy only a single row (e.g. the first occurance) containing the string to a new text file. When I use the findstr command it will copy all rows containing the string.
Thanks!
Paul Safier
Given your FINDSTR command that locates your m rows (it can be as simple or as complicated as you need)
findstr "search" "fileName.txt"
then you can process the results of that command with a FOR /F loop. You can break out of the loop after the first matching line by using GOTO.
for /f "delims=" %%A in ('findstr "search" "fileName.txt"') do (
echo %%A >>"outFile.txt"
goto :break
)
:break
The FOR command is one of the more complicated commands available to batch. There are many options. You can get help on the command by typing HELP FOR or FOR /? from a command prompt.
The "DELIMS=" option disables the parsing of the line into tokens. Without that option, the FOR /F would break each line into tokens, delimited by space or tab characters. The list of delimiters can be set to other caracter(s), or in your case, set to nothing.
The code I gave above will skip lines that begin with ; because FOR /F will skip any lines that begin with the EOL character - ; by default. You can change the EOL character to any single character. But if you don't know what your matching line might start with, then you don't know what character to use for EOL. The syntax to completely disable all token parsing and EOL line skipping is odd:
for /f delims^=^ eol^= %%A in (...) do ...
Let's say I have a batch file that has "padding" in it, and I want to indent the beginning of the prompt string for the user to type in. If I use spaces, it will not show up when run, it just ignores the spaces. This script for an example:
#echo off
echo.
echo.
echo Hi.
echo Please input something.
echo.
set /P input=
After the = there is three spaces, and what I expect is that the marker for input is away from the edge of the command box, however these spaces are ignored.
How can I fix this problem? I am using Windows 7 SP1.
You need to add a dot after the echo
The following example will output "Test" with three leading spaces:
echo. Test
Same works for tabulator. The following example will output "Test" with one leading tab:
echo. Test
As the comments above state, Vista and beyond strip leading spaces in a SET /P prompt.
The way to get around the problem is to define and use a backspace character in the prompt.
::define a variable containing a single backspace character
for /f %%A in ('"prompt $H &echo on &for %%B in (1) do rem"') do set BS=%%A
set /p var=%BS% Leading spaces will not show properly.
Normally the prompt will be at the beginning of a line, so the above works just fine.
But if the prompt is issued from the middle of a line (very unusual), then a leading character should be included prior to the <BS>, since the backspace will erase whatever was before it.
<nul set/p=Leave the cursor at the end of this line:
set /p var=.%BS% The dot (any char) is necessary to prevent the <BS> from erasing the :
Highly inspired by in dbenham's answer, I propose a similar but simpler variation based in the fact that the backspace character can be inserted in its raw form (only in batch files, attempting this in the console directly won't work as expected):
set /p var=.'BS' Leading spaces will now show properly.
The 'BS' character can be inserted by typing Alt + Numpad 008 (8 is backspace's ASCII code, won't work using the alphanumeric keys typically found above the letters), using a good text editor (such as Notepad++, Windows Notepad simply performs the backspace action).
If unable to insert the character, Notepad++ has a useful feature for this: in TextFX menu, choose TextFX Tools followed by Insert Ascii Chart or Character:
The desired character is the BS (white letters on black background on the screenshot) found in line 9 (ASCII character 8 - as stated above - as it's a zero-indexed table).
If still the result is not the one described, try changing the file encoding to ASCII. Using Notepad++:
Make a backup copy of the script or perform an experiment in a separate file, as non-ASCII characters (accented character, non-Latin etc.) are lost in this conversion.
In Encoding menu, choose Convert to ANSI
Save and check the result again...
Tested with Windows 7 Professional SP1.
Credits also go to:
#DavidCallanan for questioning the obtained result.
Wadelau for writing about Notepad++ at ufqi.com (where the screenshot was extracted from).
This works in every Windows OS from W2K + I've tried, if it suits you.
You could just use a : in the string.
set /p "var=Please input something: "
echo.%var%
dbenhams answer works good when you only want to display the text, but not if you create a file, as it inputs also the backspaces.
But for files(and for displaying) you can use copy /a to remove a CR/LF with the help of a SUB(EOF) character.
The trick is to append the SUB character directly after the text, so it's just before the CR/LF of the ECHO output.
And then using the /a switch of the copy command will only copy the content to the SUB character, so the SUB and also the CR/LF are removed
#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
You can use double quotes (" ... ") for your purpose
set /p OPTION="Your choice: "
As you can see here, the cursor for input is 3 units away.
How can I split long commands over multiple lines in a batch file?
You can break up long lines with the caret ^ as long as you remember that the caret and the newline following it are completely removed. So, if there should be a space where you're breaking the line, include a space. (More on that below.)
Example:
copy file1.txt file2.txt
would be written as:
copy file1.txt^
file2.txt
The rule for the caret is:
A caret at the line end, appends the next line, the first character of the appended line will be escaped.
You can use the caret multiple times, but the complete line must not exceed the maximum line length of ~8192 characters (Windows XP, Windows Vista, and Windows 7).
echo Test1
echo one ^
two ^
three ^
four^
*
--- Output ---
Test1
one two three four*
echo Test2
echo one & echo two
--- Output ---
Test2
one
two
echo Test3
echo one & ^
echo two
--- Output ---
Test3
one
two
echo Test4
echo one ^
& echo two
--- Output ---
Test4
one & echo two
To suppress the escaping of the next character you can use a redirection.
The redirection has to be just before the caret.
But there exist one curiosity with redirection before the caret.
If you place a token at the caret the token is removed.
echo Test5
echo one <nul ^
& echo two
--- Output ---
Test5
one
two
echo Test6
echo one <nul ThisTokenIsLost^
& echo two
--- Output ---
Test6
one
two
And it is also possible to embed line feeds into the string:
setlocal EnableDelayedExpansion
set text=This creates ^
a line feed
echo Test7: %text%
echo Test8: !text!
--- Output ---
Test7: This creates
Test8: This creates
a line feed
The empty line is important for the success. This works only with delayed expansion, else the rest of the line is ignored after the line feed.
It works, because the caret at the line end ignores the next line feed and escapes the next character, even if the next character is also a line feed (carriage returns are always ignored in this phase).
(This is basically a rewrite of Wayne's answer but with the confusion around the caret cleared up. So I've posted it as a CW. I'm not shy about editing answers, but completely rewriting them seems inappropriate.)
You can break up long lines with the caret (^), just remember that the caret and the newline that follows it are removed entirely from the command, so if you put it where a space would be required (such as between parameters), be sure to include the space as well (either before the ^, or at the beginning of the next line — that latter choice may help make it clearer it's a continuation).
⚠ Note: The first character of the next line is escaped. So if it carries any special meaning (like & or |), that meaning will be lost and it will be interpreted as a pure text character (see last example at bottom).
Examples: (all tested on Windows XP and Windows 7)
xcopy file1.txt file2.txt
can be written as:
xcopy^
file1.txt^
file2.txt
or
xcopy ^
file1.txt ^
file2.txt
or even
xc^
opy ^
file1.txt ^
file2.txt
(That last works because there are no spaces betwen the xc and the ^, and no spaces at the beginning of the next line. So when you remove the ^ and the newline, you get...xcopy.)
For readability and sanity, it's probably best breaking only between parameters (be sure to include the space).
Be sure that the ^ is not the last thing in a batch file, as there appears to be a major issue with that.
Here's an example of character escaped at the start of the next line:
xcopy file1.txt file2.txt ^
& echo copied successfully
This will not work because & will be escaped and lose its special meaning, thus sending all of "file1.txt file2.txt & echo copied successfully" as parameters to xcopy, causing an error (in this example).
To circumvent, add a space at the beginning of the next line.
Multiple commands can be put in parenthesis and spread over numerous lines; so something like echo hi && echo hello can be put like this:
( echo hi
echo hello )
Also variables can help:
set AFILEPATH="C:\SOME\LONG\PATH\TO\A\FILE"
if exist %AFILEPATH% (
start "" /b %AFILEPATH% -option C:\PATH\TO\SETTING...
) else (
...
Also I noticed with carets (^) that the if conditionals liked them to follow only if a space was present:
if exist ^
It seems however that splitting in the middle of the values of a for loop doesn't need a caret(and actually trying to use one will be considered a syntax error). For example,
for %n in (hello
bye) do echo %n
Note that no space is even needed after hello or before bye.
One thing I did not find when searching for 'how to split a long DOS batch file line' was how to split something containing long quoted text.
In fact it IS covered in the answers above, but is not obvious. Use Caret to escape them.
e.g.
myprog "needs this to be quoted"
can be written as:
myprog ^"needs this ^
to be quoted^"
but beware of starting a line with Caret after ending a line with caret - because it will come out as caret..?:
echo ^"^
needs this ^
to be quoted^
^"
-> "needs this to be quoted^"
Though the carret will be preferable way to do this here's one more approach using macro that constructs a command by the passed arguments:
#echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
set "{{=setlocal enableDelayedExpansion&for %%a in (" & set "}}="::end::" ) do if "%%~a" neq "::end::" (set command=!command! %%a) else (call !command! & endlocal)"
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
%{{%
echo
"command"
written
on a
few lines
%}}%
command is easier to read without the carets but using special symbols e.g. brackets,redirection and so on will break it. So you can this for more simpler cases. Though you can still enclose parameters in double quotes