I have a lot of variables to place in this certain command, is there a way to add many variables in it without rewriting the command?
dir c:\ /s /b /a | find "my file"
for example i want to search for "my file" and 50 other things.
thanks for the answers
In short: no. You have to rewrite the command, unless the specific command actually does accept multiple parameters (which may be variables). In your case it doesn't so you need to rewrite it.
One option would be to use findstr instead of find. You can pass multiple search patterns:
dir c:\ /s /b /a | findstr /c:"my file" /c:"other" /c:"other 2" ...
I don't know how well that scales to about "50 other things" though, but then no such solution may. Maybe you can condense the filenames to a view using regular expressions (check findstr /?).
You could also simply do:
for /R c:\ %i in ("my file" "other" "other2") do #echo %i
Both solutions bear the option for duplicates, however. They essentially search based on a "contains" semantic. So, both "C:\foo\my file" and "C:\foo\bar\my file\something.txt" would match. But then your original solution had that issue as well.
If you can make your search patterns unique or can live with false positives, than that shouldn't be an issue. But be aware of it nevertheless.
Extending Christian's suggestion to use FINDSTR instead of FIND - You can simply put all 50 search terms in a text file and reference them using the /G:"filename" option.
But there is one important caveat - There is a nasty FINDSTR bug when searching for multiple literal strings. See Why doesn't this FINDSTR example with multiple literal search strings find a match?.
As explained in the link, the work-around is to either do a case insensitive search using the /I option, or else use regular expression search terms with the /R option.
For a "complete" listing of undocumented FINDSTR features and bugs, see What are the undocumented features and limitations of the Windows FINDSTR command?.
You could wrap it in a for loop:
for %i in ("my file" "second file") do dir c:\ /s /b /a | find %i
Related
I'm using the windows command line to write my first script. I'm trying to figure out how to run a command if a filename contains a specified variable and if it doesn't then to move on to the next part of the script. The filename Doesn't have to be an exact match, it just has to contain the variable in the specified order. I've been trying all kinds of commands for hours, but to no avail. This is only my second day of scripting so i'm not very knowledgeable on much. I'm looking for a command that will do this...
if "[Craig] Christmas Day - 2009 [720p].mkv" contains "[720p]" do command
I know that contains is not actually part of the if command but this is an example i thought would be the easiest to understand.
Can anyone help me out?
echo "thenameofyourfilewhichmaybeinavariable"|find /i "the substring" >nul
if errorlevel 1 (echo missing) else (echo found)
would be the classic way - but there are others.
(the /i means "case-insensitive")
see find /? and if /? from the prompt for documentation.
I'm not well versed in batch, but a cursory search reveals the findstr command. It seems to be capable of basic pattern matching.
If your system doesn't have findstr for whatever reason, you can use a messy equality check. Example adapted from this answer:
#setlocal enableextensions enabledelayedexpansion
set str1="[720p]"
if not x%str1:bcd=%==x%str1% echo 'It contains [720p]'
endlocal
I have an input file that looks like:
application database variable value
+-------------------+-------------------+-------------------+-------------------
O_PrTot Rptg ClosedMonthsFY13 Jan:Dec
O_PrTot Rptg OMNICORE_Year FY14
O_PrTot Rptg ClosedMonthsFY14 Jan:Oct
I need to find value for ClosedMonthsFY14 which is Jan:Oct and place this output
into .txt file.
Thanks
Based on your title "Ouput the entire line based on matching string" and your comment "and place this output into .txt file", this should work. We make use of the FINDSTR command, which according to the TechNet article I linked, "searches for patterns of text in files using regular expressions." We don't particularly need a regular expression in this case, but it will work nonetheless:
FINDSTR /I "ClosedMonthsFY14" C:\path\to\input.txt > C:\path\to\output.txt
The switch /I means make the search case-insensitive.
#ECHO OFF
SETLOCAL
FOR /f "tokens=3,4" %%a IN (q27307586.txt) DO IF /i "%%a"=="ClosedMonthsFY14" SET "outstring=%%b"
ECHO %outstring%
FOR /f "delims=" %%a IN ('findstr /i "ClosedMonthsFY14" q27307586.txt') DO SET "outstring2=%%a"
ECHO %outstring2:~61%
GOTO :EOF
I used a file named q27307586.txt containing your data for my testing.
There are two different methods here. The first method relies on the assumption that each column contains exactly one string which does not include separators like spaces or commas.
The second method uses the column-position; 61 characters in the selected line are skipped and the remainder assigned to the variable.
To actually output the variable to a file, simply append >"filename" to the appropriate echo line
Note that the second method will retain the trailing spaces on the line, which may or may not be appropriate for your purpose.
The /i switch in each case makes the string-match case-insensitive.
(Your question header states "the entire line" but your narrative says you need to find the value)
I'm trying to create a batch that creates a fileC.txt containing all lines in fileA.txt except for those that contains the strings in the lines in fileB.txt:
Pseudo:
foreach(line L in fileA.txt)
excluded = false
foreach(string str in fileB.txt)
if L contains str
exclude = true
if !excluded
add L to fileC.txt
if L !contains
For example
fileA.txt: (all)
this\here\is\a\line.wav
and\this\is\another.wav
i\am\a\chocolate.wav
peanut\butter\jelly\time.wav
fileB.txt: (those to be excluded)
another.wav
time.wav
fileC.txt: (wanted result)
this\here\is\a\line.wav
i\am\a\chocolate.wav
I've been fiddling around with FINDSTR but I just can't seem to puzzle it together.. any help or pointers greatly appreciated!
Cheers!
/ Fredde
The answer should be this simple:
findstr /lvg:"fileB.txt" "fileA.txt" >fileC.txt
And with your example, the above does give the correct results.
But there is a nasty FINDSTR bug that makes it unreliable when using multiple case sensitive literal search strings. See Why doesn't this FINDSTR example with multiple literal search strings find a match?, as well as the answer that goes with it. For a "complete" list of undocumented FINDSTR features and bugs, see What are the undocumented features and limitations of the Windows FINDSTR command?.
So the simple code above can fail depending on the content of the files. If you can get away with using a case insensitive search, then the solution is simple.
findstr /livg:"fileB.txt" "fileA.txt" >fileC.txt
Edit: Both versions above will fail if fileB.txt contains \\ or \". In order to work properly, those strings must be escaped as \\\ and \\"
But if you must use a case sensitive search, then there is no simple solution. Your best bet for a pure batch solution might be to use the /R regular expression option. But then you will have to create a modified version of fileB.txt where all regex meta-characters are escaped so that the strings give the correct literal search. That is a mini project in and of itself.
Perhaps your best option for a case sensitive solution is to get a 3rd party tool like grep or sed for Windows.
Edit: Here is a reasonably performing pure batch solution that is nearly bullet proof
I looked into doing something like the proposed logic in your question. But using batch to read all lines in a file is relatively slow. This solution only reads the exclude file line by line. It uses FINDSTR to read the lines in "fileA.txt" repeatedly, once per search string. This is a much faster algorithm for a batch file.
The traditional method to read a file is to use a FOR /F loop, but there is another technique using SET /P that is faster, and it is safe to use with delayed expansion. The only limitations to this method are:
It strips trailing control characters from the line
It is limited to 1021 bytes per line
Each line must be terminated by <CR><LF> as is the Windows standard. It will not work with unix style lines terminated by <LF>
The search strings must have each \ and " escaped as \\ and \" when they are used with the /C option.
#echo off
setlocal enableDelayedExpansion
copy fileA.txt fileC.txt >nul
for /f %%N in ('find /c /v "" ^<fileB.txt') do set len=%%N
<fileB.txt (
for /l %%N in (1 1 !len!) do (
set "ln="
set /p "ln="
if defined ln (
set "ln=!ln:\=\\!"
set ln=!ln:"=\"!
move /y fileC.txt temp.txt >nul
findstr /lv /c:"!ln!" temp.txt >fileC.txt
)
)
)
del temp.txt
type fileC.txt
I'd like to recursively search a directory and find files, which have NOT a certain extension, or precisely, which have NOT a certain set of extensions.
Sketch: find in "dir" all files without "ext1", "ext2", "ext3" and print results to .txt
I tried around several hours with DIR and ATTRIB, but unfortunately without bigger success.
Your consideration is highly regarded! Thanks.
Try this:
dir /b /s /a-d | findstr /vi ".ext1$ .ext2$ .ext3$"
The /a-d switch excludes directories, giving you only files. The findstr parameter lets you search the files for strings, and the /vi switch indicates to exclude files containing the next parameter, the search being case insensitive.
As Joey pointed out, the $ is necessary to indicate end of the line.
I'm doing a little string validation with findstr and its /r flag to allow for regular expressions. In particular I'd like to validate integers.
The regex
^[0-9][0-9]*$
worked fine for non-negative numbers but since I now support negative numbers as well I tried
^([1-9][0-9]*|0|-[1-9][0-9]*)$
for either positive or negative integers or zero.
The regex works fine theoretically. I tested it in PowerShell and it matches what I want. However, with
findstr /r /c:"^([1-9][0-9]*|0|-[1-9][0-9]*)$"
it doesn't.
While I know that findstr doesn't have the most advanced regex support (even below Notepad++ which is probably quite an achievement), I would have expected such simple expressions to work.
Any ideas what I'm doing wrong here?
This works for me:
findstr /r "^[1-9][0-9]*$ ^-[1-9][0-9]*$ ^0$"
If you don't use the /c option, the <Strings> argument is treated as a space-separated list of search strings, which makes the space a sort of crude replacement for the | construct. (As long as your regexes don't contain spaces, that is.)
Argh, I should have read the documentation better. findstr apparently doesn't support alternations (|).
So I'm probably back to multiple invocations or replacing the whole thing with a custom parser eventually.
This is what I do for now:
set ERROR=1
rem Test for zero
echo %1|findstr /r /c:"^0$">nul 2>&1
if not errorlevel 1 set ERROR=
rem Test for positive numbers
echo %1|findstr /r /c:"^[1-9][0-9]*$">nul 2>&1
if not errorlevel 1 set ERROR=
rem Test for negative numbers
echo %1|findstr /r /c:"^-[1-9][0-9]*$">nul 2>&1
if not errorlevel 1 set ERROR=
Or if you can, download grep for windows.. Many more features than findstr provides.
A simpler regex that achieves the same thing is possible, just add an optional minus to the start of your original expression:
^-?[0-9][0-9]*$
Support for regex in findstr is quite limited. I suggest using Notepad++. The find in files option supports Perl Compatible Regular Expressions; results showing filename, line number and matching text can be easily copied to a text file.