How can I insert a command result in the same "echo" line? - batch-file

I would like to create a logfile with this information :
echo %time%;%date%;%computername%;"findstr /I "%%a" %MYFILES%\Dir_ALL.txt" >> %computername%_File.csv
How can I write something that will not write "findstr /I ..." but the output of this command ?
I would like to have everything in the same line on my output file.
Thank you

write a line without linefeed with set /p, followed by the second line:
<nul set /p .=%time%;%date%;%computername%;>>%computername%_File.csv
findstr /I "%%a" %MYFILES%\Dir_ALL.txt>>%computername%_File.csv
Note: Because of the %%a I guess, you are using this codefragment inside a forstatement. I suggest using !time! instead of %time% to get the actual time (using delayed expansion of course)

You have to set a variable with the command result. This is answered in Windows Batch help in setting a variable from command output, using a dummy for-loop whose loop variable is set from the content of a file.
That would be something like this:
findstr /I "%%a" %MYFILES%\Dir_ALL.txt >%temp%\temp.txt
for /f %%i in (%temp%\temp.txt) do echo %time%;%date%;%computername%;%%i >> %computername%_File.csv
del %temp%\temp.txt
There is a limitation on this: the variable cannot contain multiple lines. However, rephrasing your script fragment as a loop would probably solve that issue as well.
The MSDN article on set shows some additional features which you can use to control how the data from the file is parsed. Normally it parses the result into tokens separated by spaces. But you can override that using the delims keyword.

Related

Windows Batch-file echo a modified string

I am looping through a series of sub-directories using a for loop
For /R %1 %%f IN (*.shp) do (
I need to convert the file path %%f from a backslash to a forward slash.
set old=%%f
set new=!old:\=/!
echo !new!
echo|(set /p="CALL spatial.importShapefileToLayer('%%~nf', '!new!');" & echo.) >> test.cypher
As the code is now, the !new! text is written as a literal to the test.cypher
CALL spatial.importShapefileToLayer('N00E006_D100_S004_T007_L00_U0_R0', '!new!');
What I need to write to the output is the value of !new!
CALL spatial.importShapefileToLayer('N00E006_D100_S004_T007_L00_U0_R0', 'c:/test/N00E006_D100_S004_T007_L00_U0_R0.shp');
The echo of the !new! to the screen does show the correction of backslash to forward slash, so the !new! variable is receiving the correction
Ideas on how to correctly use the !new! contents in the output string would be appreciated.
edit : setlocal EnableDelayedExpansion
was included in the batch file
Somebody smarter than I am will likely direct you to How does the Windows Command Interpreter (CMD.EXE) parse scripts? for an explanation about why this is happening, but as far as I can tell, the parentheses (or maybe the pipe) are causing things to get expanded and processed in the wrong order so !new! never has a chance to get expanded properly.
To fix this, move the ( to the start of the line.
#echo off
setlocal enabledelayedexpansion
if exist test.cypher del test.cypher
for /r "%~1" %%A in (*.shp) do (
set old=%%A
set new=!old:\=/!
echo !new!
(echo|set /p="CALL spatial.importShapefileToLayer('%%~nA', '!new!');" & echo.) >> test.cypher
)

How to get the FIND command output count value into a variable in batch scripting?

I am using a command:
find /c "abc" "C:\Users\abc\Desktop\project\string.txt"
Output:
---------- C:\Users\abc\Desktop\project\string.txt: 4
I want to assign this value 4 to a variable so that I can use it for an if statement.
I would use:
For /F %%A In ('Find /C "abc"^<"C:\Users\abc\Desktop\project\string.txt"') Do (
Set "mlc=%%A")
Your %mlc% varaiable would hold the matched line count.
I'm not sure if this is the best method to do this, but it works:
find /c "abc" "C:\Users\abc\Desktop\project\string.txt" > tmpFile
set /p myvar= < tmpFile
del tmpFile
with your snytax the output is ---------- C:\Users\abc\Desktop\project\string.txt: 4
There is another syntax: type file.txt|find /c "abc", which gives you a beautiful output of just:
15
To get it into a variable, use a for /f loop:
for /f %%a in ('type file.txt^|find /c "abc"') do set count=%%a
echo %count%
(for use directly on commandline (not in a batchfile) use %a instead of %%a)
I am not a batch script / Windows command line pro, but I got this to work with the following, without a temporary file:
for /f "delims=" %%a in ('dir "%~dpSomeFolder\*.suffix" /b ^|find /c "suffix"') do set "fileCount=%%a"
Explanation:
I found it very confusing, why assigning a variable with a batch script, is so weird, considering it's "Windows", the most used operating system. Anyways this answer here is helpful. Even if it is a duplicate, I like the formatting more:
Assign command output to variable in batch file
%~dp0: basically translates to "path of this script". You can find info about this online.
SomeFolder\*.suffix: In my case this I was looking to count the number of files ending with a certain suffix. I had problems using the dir command with \s as this listed all the matches in subfolders I did not expect him too look. As if this was referenced to the path from which I executed this script from. Therefore, the path name with the asterisk "\*.suffix" solved that issue for me.
^|: When using the pipe sign "|" in "for command", specified inside the single quotation marks, you need to use a circumflex "^|", instead of just the "|", which you would normally use when just typing in the command in cmd (f.e. like dir "%~dp0Folder*.suffix" /b | find /c "suffix"
%%a: You have to use the "double percentage", as this is just a locale variable when writing this in a batch script.
FYI: you can have a look at the command help/ manual ("man" as I am used to Linux), with the command /? (f.e. dir /? or find /?)
I thought I would also mention how I then used this variable, as this might save some time for you ;) (batch code coloring somehow did not work here...).
IF %fileCount% NEQ 1 (ECHO Number of SUFFIX files does not equal 1! Found %fileCount% SUFFIX files inside the SomeFolder. Aborting script! & PAUSE & EXIT)

Executing command, getting output and using it

I'm trying to do a Windows batch file that excecute a command and pass to it a flow param that is received as a parameter of the batch file, then I need to get the output of this execution and do something with it before sending it to the batch output (cuting the output to get the first character only).
This is what I have so far:
for /f %%i in ('"C:\Program Files (x86)\JAM Software\SpamAssassin for Windows\spamc.exe" < %1') do set RES2 = %%i
ECHO %RES2~0,1%
But it is not working as I expect. Thanks for the help.
for /f %%i in (
'"C:\Program Files (x86)\JAM Software\SpamAssassin for Windows\spamc.exe" ^< %1'
) do set RES2=%%i
ECHO %RES2:~0,1%
There are three changes in your code. The colon in the echo line (needed, it is part of the sintax), the escaped redirection and the spaces removed around the equal sign in the set line. With spaces, the variable name contains a space and the value inside the variable also have a space in it (and it will be the first, so the later echo command will fail)

replace characters in TXT file using batch?

I don’t know if this is possible but I would like to make a batch, which replaces all, the backslashes contained in a txt file (C:\locations) with forward slashes.
THX..
EDIT:
Im trying to loop:
set str1=!Var1!
echo.%str1%
set str1=%str1:\=/%
to work together with:
set file=C:\text1.txt
FOR /F %%i IN (%file%) DO (
set username=%%i
echo (load "%%i") >> C:\text.txt
)
what I have so far is:
ECHO Retreving list of files...
dir /s /b c:\ICT\AUTOCAD_2010\*.LSP > C:\BART1.txt
Echo Looping variables...
set file=C:\text1.txt
FOR /F %%1 IN (%file%) DO (
set fred=%%1
echo %%1 > C:\tempme.txt
)
set fred=C:\tempme.txt
set fred=%fred:\=/%
echo (load "%fred%") >> C:\text2.txt
however this returns:
(load "C:/tempme.txt")
which is incorect.
Windows' PowerSheel is too limited for that. I suggest you using a scripting language like Perl. Here's a quick script that does that:
my #file = <STDIN>;
my $text = join('', #file);
$text =~ s/\\/\//g;
print($text);
You can launch it like
perl foo.pl < example.txt > result.txt
Using sed as suggested by Tichodroma is another very good option.
I'm a little confused as to what you really want. Your sample code has a FOR ... IN that only has one file in the IN (), i.e. the content of %fred%. Then you write that one filename into a temporary file. Afterwards you have SET that replaces the backslash with a forward slash in the name of the temporary file. But this never touches any file.
However, in your opening segment you want to replace backslashes with forward slashes in a file. So I'm focusing on that part. That would be done this way:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
REM Here's a backslash: \
FOR /F "delims=" %%a IN ('TYPE %0') DO (
SET line=%%a
ECHO !line:\=/!
)
Please note that for simplicity this little batch file parses itself (%0) and, therefore, only replaces that one backslash. However, feel free to put whichever file next to TYPE.
EnableDelayedExpansion makes the syntax with the ! work (see SET /? for more info about delayed expansion). TYPE obviously writes a file to the console. The FOR /F "delims=" now grabs the output of that line per line (since delims= defines no delimiter for the tokenizer of FOR). The line-variable is necessary, because I don't think that there is a proper way to make the ECHO-line work with %%a.
The only downside is that this will remove all empty lines from the original file. I don't know if that's a problem for you.

Windows Batch help in setting a variable from command output [duplicate]

This question already has answers here:
Set output of a command as a variable (with pipes) [duplicate]
(6 answers)
Closed 7 years ago.
I need to run a simple find command and redirect the output to a variable in a Windows Batch File.
I have tried this:
set file=ls|find ".txt"
echo %file%
But it does not work.
If I run this command it works without problems:
set file=test.txt
echo %file%
So obviously my command output is not being set to my variable. Can anyone help? Thanks
I just find out how to use commands with pipes in it, here's my command (that extracts the head revision of an svn repo) :
SET SVN_INFO_CMD=svn info http://mySvnRepo/MyProjects
FOR /f "tokens=1 delims=" %%i IN ('%SVN_INFO_CMD% ^| find "Revision"') DO echo %%i
First of all, what you seem to expect from your question isn't even possible in UNIX shells. How should the shell know that ls|find foo is a command and test.txt is not? What to execute here? That's why UNIX shells have the backtick for such things. Anyway, I digress.
You can't set environment variables to multi-line strings from the shell. So we now have a problem because the output of ls wouldn't quite fit.
What you really want here, though, is a list of all text files, right? Depending on what you need it's very easy to do. The main part in all of these examples is the for loop, iterating over a set of files.
If you just need to do an action for every text file:
for %%i in (*.txt) do echo Doing something with "%%i"
This even works for file names with spaces and it won't erroneously catch files that just have a .txt in the middle of their name, such as foo.txt.bar. Just to point out that your approach isn't as pretty as you'd like it to be.
Anyway, if you want a list of files you can use a little trick to create arrays, or something like that:
setlocal enabledelayedexpansion
set N=0
for %%i in (*.txt) do (
set Files[!N!]=%%i
set /a N+=1
)
After this you will have a number of environment variables, named Files[0], Files[1], etc. each one containing a single file name. You can loop over that with
for /l %%x in (1,1,%N%) do echo.!Files[%%x]!
(Note that we output a superfluous new line here, we could remove that but takes one more line of code :-))
Then you can build a really long line of file names, if you wish. You might recognize the pattern:
setlocal enabledelayedexpansion
set Files=
for %%i in (*.txt) do set Files=!Files! "%%i"
Now we have a really long line with file names. Use it for whatever you wish. This is sometimes handy for passing a bunch of files to another program.
Keep in mind though, that the maximum line length for batch files is around 8190 characters. So that puts a limit on the number of things you can have in a single line. And yes, enumerating a whole bunch of files in a single line might overflow here.
Back to the original point, that batch files have no way of capturing a command output. Others have noted it before. You can use for /f for this purpose:
for /f %%i in ('dir /b') do ...
This will iterate over the lines returned by the command, tokenizing them along the way. Not quite as handy maybe as backticks but close enough and sufficient for most puposes.
By default the tokens are broken up at whitespace, so if you got a file name "Foo bar" then suddenly you would have only "Foo" in %%i and "bar" in %%j. It can be confusing and such things are the main reason why you don't ever want to use for /f just to get a file listing.
You can also use backticks instead of apostrophes if that clashes with some program arguments:
for /f "usebackq" %%i in (`echo I can write 'apostrophes'`) do ...
Note that this also tokenizes. There are some more options you can give. They are detailed in the help for command.
set command has /p option that tells it to read a value from standard input. Unfortunately, it does not support piping into it, but it supports reading a value from a first line of existing file.
So, to set your variable to the name of a first *.txt file, you could do the following:
dir /b *.txt > filename.tmp
set /p file=< filename.tmp
del /q filename.tmp
It is important not to add a space before or even after =.
P. S. No fors, no tokens.
Here's a batch file which will return the last item output by find:
#echo off
ls | find ".txt" > %temp%\temp.txt
for /f %%i in (%temp%\temp.txt) do set file=%%i
del %temp%\temp.txt
echo %file%
for has a syntax for parsing command output, for /f "usebackq", but it cannot handle pipes in the command, so I've redirected output to a temporary location.
I strongly recommend, given that you have access to ls, that you consider using a better batch language, such as bash or even an scripting language like python or ruby. Even bash would be a 20x improvement over cmd scripting.
The short answer is: Don't!
A windows shell env var can hold a max of 32 Kb and it isn't safe to save output from programs in them.
That's why you can't. In batch script you must adopt another programming style. If you need all of the output
from the program then save it to file. If you only need to check for certain properties then pipe the output into
a program that does the checking and use the errorlevel mechanism:
#echo off
type somefile.txt | find "somestring" >nul
if %errorlevel% EQU 1 echo Sorry, not found!
REM Alternatively:
if errorlevel 1 echo Sorry, not found!
However, it's more elegant to use the logical operators Perl style:
#echo off
(type somefile.txt | find "somestring" >nul) || echo Sorry, not found!
It's not available in DOS, but in the Windows console, there is the for command. Just type 'help for' at a command prompt to see all of the options. To set a single variable you can use this:
for /f %%i in ('find .txt') do set file=%%i
Note this will only work for the first line returned from 'find .txt' because windows only expands variable once by default. You'll have to enable delayed expansion as shown here.
what you are essentially doing is listing out .txt files. With that, you can use a for loop to over dir cmd
eg
for /f "tokens=*" %%i in ('dir /b *.txt') do set file=%%i
or if you prefer using your ls, there's no need to pipe to find.
for /f "tokens=*" %%i in ('ls *.txt') do set file=%%i
Example of setting a variable from command output:
FOR /F "usebackq" %%Z IN ( `C:\cygwin\bin\cygpath "C:\scripts\sample.sh"` ) DO SET BASH_SCRIPT=%%Z
c:\cygwin\bin\bash -c '. ~/.bashrc ; %BASH_SCRIPT%'
Also, note that if you want to test out the FOR command in a DOS shell, then you need only use %Z instead of %%Z, otherwise it will complain with the following error:
%%Z was unexpected at this time.

Resources