I'd like to be able to search files on a Windows machine using the command line instead of the GUI interface. For example, on Linux, I use:
find . -name "*.c" -exec grep -Hn "sqlcommand" {} \;
Is there something similar with Windows?
After long time working with Unix systems I had to make some scripts on Windows.
For serious scripting Powershell is the tool you should use.
You can search Internet with keywords like powershell find string in file,
or other combinations and you find a lot of information.
That's the problem, a simple oneliner like
get-childitem C:\yourdir -include *.c -recursive |Select-String -pattern sqlcommand
won't help you much. You need to find the PowerShell IDE, learn the different syntax and try to love / accept that new stuff.
Prepare for a study with PowerShell when you want to do these things more often, or try to get a Unix-like environment on your windows (cygwin, or better git for windows)
NEW AND IMPROVED ANSWER
I recently stumbled upon a built-in command that is rather similar to find in Unix:
ForFiles
Basic syntax is:
forfiles [/p <Path>] [/m <SearchMask>] [/s] [/c <Command>] [/d [{+|-}][{<Date>|<Days>}]]
There are several variables to use when constructing the command to execute per each file (via the /c switch):
#FILE File name.
#FNAME File name without extension.
#EXT File name extension.
#PATH Full path of the file.
#RELPATH Relative path of the file.
#ISDIR Evaluates to TRUE if a file type is a directory. Otherwise, this variable evaluates to FALSE.
#FSIZE File size, in bytes.
#FDATE Last modified date stamp on the file.
#FTIME Last modified time stamp on the file.
It looks like you would use the command like this:
FORFILES /m *.cs /c FINDSTR /I /N /C:"sqlcommand" #FILE
I'm not sure how long this command has been around, but the earliest reference I could find in the documentation is from 2008-09-02:
https://web.archive.org/web/20080902221744/http://technet.microsoft.com:80/en-us/library/cc753551.aspx
and that page states that it was last updated on "April 25, 2007". The documentation is filed under "Windows Server" so it likely started there and was added to the desktop OSes starting with Windows Vista, I believe. I did check Windows XP and didn't see it there, though it is on Windows 10.
ORIGINAL ANSWER
This requires a combination of two DOS commands:
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
and
DIR /B /O:N /W *.c (this is the 'command' noted in the FOR command above)
Create a CMD script as follows:
#ECHO OFF
FOR /F %%B IN ('DIR /B /O:N /W *.cs') DO (
findstr /I /N /C:"sqlcommand" %%B
)
OR, just use the find command found in this set of Unix command ports:
http://unxutils.sourceforge.net/
or
http://sourceforge.net/projects/unxutils/
(both links should be the same project)
Related
I need to convert some xls files into xlsx files. I can successfully convert one xls file into xlsx by running this command into cmd prompt (windows):
ssconvert inputFileName.xls outputFileName.xlsx
(ssconvert is a Gnumeric's command-line utility that can convert between different spreadsheet file formats)
I'd like to write a batch file that FOR EACH file in a specified directory runs the command I wrote above, using the current file name both for input and for output filename.
For example, if I have this set of files:
c:\directory\file1.xls
c:\directory\file2.xls
c:\directory\file3.xls
the output should be
c:\directory\file1.xlsx
c:\directory\file2.xlsx
c:\directory\file3.xlsx
so the batch pseudo code should be something like
directory = c:\directory\
for (fileName in directory)
ssconvert fileName.xls fileName.xlsx
Can anyone help me?
for /r %%v in (*.xls) do ssconvert "%%v" "%%vx"
a couple have people have asked me to explain this, so:
Part 1: for /r %%v in (*.xls)
This part returns an array of files in the current directory that have the xls extension. The %% may look a little curious. This is basically the special % character from command line as used in %PATH% or %TEMP%. To use it in a batch file we need to escape it like so: %%PATH%% or %%TEMP%%. In this case we are simply escaping the temporary variable v, which will hold our array of filenames.
We are using the /r switch to search for files recursively, so any matching files in child folders will also be located.
Part 2: do ssconvert "%%v" "%%vx"
This second part is what will get executed once per matching filename, so if the following files were present in the current folder:
c:\temp\mySheet.xls,
c:\temp\mySheet_yesterday.xls,
c:\temp\mySheet_20160902.xls
the following commands would be executed:
ssconvert "c:\temp\mySheet.xls" "c:\temp\mySheet.xlsx"
ssconvert "c:\temp\mySheet_yesterday.xls" "c:\temp\mySheet_yesterday.xlsx"
ssconvert "c:\temp\mySheet_20160902.xls" "c:\temp\mySheet_20160902.xlsx"
Actually this is pretty easy since Windows Vista. Microsoft added the command FORFILES
in your case
forfiles /p c:\directory /m *.xls /c "cmd /c ssconvert #file #fname.xlsx"
the only weird thing with this command is that forfiles automatically adds double quotes around #file and #fname. but it should work anyway
you can run something like this (paste the code bellow in a .bat, or if you want it to run interractively replace the %% by % :
for %%i in (c:\directory\*.xls) do ssconvert %%i %%i.xlsx
If you can run powershell it will be :
Get-ChildItem -Path c:\directory -filter *.xls | foreach {ssconvert $($_.FullName) $($_.baseName).xlsx }
I am doing similar thing to compile all the c files in a directory.
for iterating files in different directory try this.
set codedirectory=C:\Users\code
for /r %codedirectory% %%i in (*.c) do
( some GCC commands )
I want to start acrobat from my software.
At this moment I'm using the following command:
cmd /c start AcroRd32.exe /t filename
But now acrobat sometimes updates to 64 bit version and then AcroRd32.exe doesn't exists anymore.
So we have to start acrobat.exe instead:
cmd /c start acrobat.exe /t filename
But we are working with a lot of clients with different computers and maybe different versions of acrobat. That is also why we don't specify an install path.
So is there a way to say in one command line entry (not a script) to start AcroRd32.exe and if this doesn't work start immediately acrobat.exe instead?
So something like:
cmd /c start AcroRd32.exe /t filename | if not 1 is ok then cmd /c start acrobat.exe /t filename
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%b IN ('where autoruns64.exe autorunsc64.exe 2^>nul') DO CMD /c START "" "%%b" &GOTO done
ECHO NOT found!
:done
GOTO :eof
Note: START command : extra pair of quotes. This sets the title of the STARTed session, otherwise the first "quoted string" is used.
"%%b" is used in case the path to the executable (I used autoruns) contains a space.
The first argument to where is the preferred target.
where examines the path for filenames matching its arguments and lists them. The for /f reads the list and on the first match found, executes the START. If no match is found,an error message is produced by WHERE, which is suppressed by the 2^>nul.
Edit: one-line version
FOR /f "delims=" %b IN ('where autoruns64.exe autorunsc64.exe 2^>nul') DO CMD /c START "" "%b" &exit
Posted as a batch file because it's easier to re-run during testing.
WHERE locates files on the PATH and lists them
START locates files on the PATH and executes the first one found.
The PATH is the list of directories that will be examined by START, in the order in which they will be searched for the required executable, so WHERE examines that list of directories for the target executable, it does not search all of the drives in the hope of finding it.
Traditionally even on 64bit it was still Acrord32 for the free reader to avoid such dual name problems / complication and the 32bit or 64bit full product was start Acrobat.exe
However Adobe did not help by using version specifics within the registry so a query there would generally produce differing results ! Microsoft start adding enhancements as to where or how simple launchers may be deployed so the location now gets cloudier (pun :-)
However the traditional ask the registry works best except for my portable
version (where /r h:\ acrord32.exe is very slow on a TB drive and it was not on that one anyway, it was on a network drive!).
Simplest way I can think of via cmd to find an installed copy is:-
cmd /v:on /c "where acro*.exe>temp.txt&&set /p acroexe=<temp.txt&&if exist !acroexe! (!acroexe! /t %filename%)"
there is little use of errorlevel since the fail will simply report
> INFO: Could not find files for the given pattern(s).
Priority will be the first match within %path%
You also need to consider where temp.txt will be written perhaps "%tmp%\delme.txt"
Potential "Gotcha" is if first match finds something like AcrobatUpdater.exe
To avoid random acro's best use
cmd /v:on /c "where /f acrord32.exe acrobat.exe>temp.txt&&set /p acroexe=<temp.txt&&if exist !acroexe! (!acroexe! /t %filename%)"
actually since all you desire is start one or the other then
start "Reader" acrord32.exe /t "filename.pdf" "printer name"||start "Editor" acrobat.exe /t "filename.pdf" "printer name"
The downside to this last method is Windows will raise a GUI error if acrord32 cannot "start" Thus gui warning needs to be dismissed before the second option can be run and start. In that case START cannot be told to be silent on error.
Finally make your choice from above or use a hybrid approach
where /f acrord32.exe... || start acrobat.exe.. will not warn user on first fail but only on second if both missing.
was wandering if there is a way to extract a line of text which contains certain value from a .txt file using CMD. For example using "type filepath\example.txt" will open the whole file and in my case I am working trough a software which doesn't allow CTRL+F option and .txt files are massive.
Is there any way I could specify certain word in order to get that whole line of text or to open only .txt files which have that word within them. For example I have 1000 .txt files and all of them contain the same text but only one of them has a word "EXAMPLE" in it. Could I use some command to find and open that file using CMD.
Thank you.
I have 1000 .txt files and all of them contain the same text but only one of them has a word "EXAMPLE" in it. Could I use some command to find and open that file using CMD.
a) find the file(s) that have the desired string:
findstr /m "EXAMPLE" *.txt
b) find the file (assuming, only one contains the string; else it will open all matching files) and open the file in notepad:
for /f "delims=" %a in ('findstr /m "EXAMPLE" *.txt') do "%a"
c) find the one line that has the string:
findstr "EXAMPLE" *.txt
The findstr.exe solution from Stephen would be less typing. But, using Select-String allows the use of a much more complete implementation of regex. All supported Windows systems have PowerShell available. This works in a batch-file run by cmd on windows and at the command prompt. Given that this would likely be put into a batch-file, the amount of typing is not very significant.
#powershell.exe -NoLogo -NoProfile -Command ^
Get-ChildItem -Path '.\*.txt' ^| ^
ForEach-Object { Select-String -Pattern 'example' -Path $_ } ^| ^
Select-Object -Property Filename,Line
Not the most elegant alternative, I agree, and I am certain someone will tell me how it could be bettered. The key is it uses basic find a string (you can set as I have to be case insensitive) in a file then reports filename and line number, Line [9] in this case.
#forfiles /m *.txt /C "cmd /c (find /n /i \"For example\" "#file"1>nul) &&if %errorlevel%==0 (find /n /i \"For example\" "#file"2>nul)"
When used in a batch file it could look something like this, but see caveats below
Finder$.cmd
#echo off & Title Find wally String in a file
set "string=where's Wally"
if not "%1"=="" set "string=%~*"
forfiles /m *.txt /C "cmd /c (find /n /i \"%string%\" "#file"1>nul) &&if %errorlevel%==0 (find /n /i \"%string%\" "#file")"
echo/ & pause & exit /b
It is not perfect but note its not case sensitive (using /i), it can readily fail if *.txt files are not plain text and as written will only accept a short unquoted string of up to 9 words ( avoid " or other punctuation). It works in local directory with *.txt, but you could alter those as require to first say cd /d f:\mylogs and search *.log files.
Finally you asked to open the file thus we can simplify for that task to call an editor like notepad or with some fetteling one that accepts line numbers (but that is another question)
forfiles /m *.txt /C "cmd /c (find /n /i \"%string%\" "#file"1>nul) &&if %errorlevel%==0 (notepad.exe "#file")"
Everything below is related to unix bash terminal, so please install Linux Subsystems if you are using Windows. Or even Linux itself :)
You can open specific file in a text editor like Vim or Nano in terminal. They offer the "CTRL+F" function.
Below you can see me searching for the "gameId" keyword in the file game_stats.js, which I opened via $ vim game_stats.js.
P.S. To quite vim you need to type :q :)
Use grep command as advised in this answer https://stackoverflow.com/a/16957078/13212398
Example for the command that recursively searches for any .js or .txt files that contains "let" in the current directory (.).
$ grep --include=\*.{js,txt} -rnw -e "let" .
./this_test.js:18:let bob = new Person('Bob');
./this_test.js:19:let bill = new Person('Bill', bob);
./TUD-2Q-WDB/checkers-in-delft/public/javascripts/game_state.js:99: let pieces = []
Goal: I want to use CMD.EXE to find a single MSI, located in C:\ProgramData - not elsewhere - and then execute it.
My attempt: dir /s /b C:\programdata\*"my program"*.msi | explorer
Problem: Explorer opens but doesn't launch my MSI.
Constraints: I can't write a .BAT. So this must run on the command line.
Although that doesn't surprise me, I apparently don't understand CMD.EXE and piping well enough to do this. Any guidance?
A *.msi file is not an executable. It is a compiled installer script file which needs an interpreter for execution. The interpreter is msiexec.exe.
Searching for a file can be done with command DIR or with command FOR.
The better solution using command FOR:
for /R C:\ProgramData %# in ("my program*.msi") do %SystemRoot%\System32\msiexec.exe /i "%#"
The more complicated solution using the commands DIR and FOR:
for /F "delims=" %# in ('dir /A-D /B /S "C:\ProgramData\my program*.msi" 2^>nul') do %SystemRoot%\System32\msiexec.exe /i "%#"
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
for /?
msiexec /?
Note: %%# instead of %# would be needed if one of the two command lines is used within a batch file.
I need an equivalent way in a Windows CLI to do what I would be able to in Linux/UNIX in piping through to show unique values.
I don't think there is a command as such, from what I can gather, so is there another way to do this?
What I have to achieve is to list files from multiple directories (whether they exist or not, which I currently do using dir). The way that the script (for the requesting application) works uses multiple sources to construct a directory list and subsequently the command depending on whether the platform is Windows or UNIX but the danger here is that there is a possibility of duplicate directories in the list and this would skew the results at the other end.
The easiest way to deal with this is to do it at source, i.e. the original command being run. So in Linux, the command structure is more or less:
find [dir] [dir] [dir] | grep file_name | sort -u
Doing the same in Windows is obviously more difficult given that:
it has to be a native read only command/script string you would use from Windows Command Prompt (cmd.exe)
I can't install anything on the hosts this is run on
I can't create temporary text files as part of the process
Microsoft has added a /unique switch to sort.exe in Windows 10 but has forgotten to update its documentation. I tested this switch on Windows 7, Windows 8.1 and Windows 10 v1709. It was present in the latter but absent from the first two.
So, sort.exe /unique is the equivalent of UNIX sort -u.
PowerShell already has a Sort-Object cmdlet that supports a -Unique switch. Better still, by default, PowerShell defines the alias sort for Sort-Object so, | sort -unique is pretty much all you need.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(
SET "line="
FOR /f "delims=" %%a IN ('sort q22351713.txt') DO (
IF "!line!" neq "%%a" ECHO(%%a
set "line=%%a"
)
)>newfile.txt
GOTO :EOF
I used a file named q22351713.txt for my testing.
Produces newfile.txt
Not bullet-proof
Always better to explain what the original does rather than assume it's obvious.
Dirty batch is dirty...
%COMSPEC% /d /v:on /c "(SET LASTLINE=) & (FOR /f "usebackq tokens=*" %L IN (`DIR /b /s /-p dir1 dir2 dir3 dir3 dir2 dir1 "dir with space" ^| %SYSTEMROOT%\system32\find.exe /i "search_file_name" ^| %SYSTEMROOT%\system32\sort.exe`) DO #((IF /i NOT "{!LASTLINE!}"=="{%~L}" ECHO %~L) & SET "LASTLINE=%~L"))"
Let's break this down a bit...
%COMSPEC% /d /v:on /s /c "..." - you wanted a single command, not a batch, and we needed delayed expansion (/v:on), so we invoke a subshell using the known executable of the Windows Command Prompt (%COMSPEC%). We don't want to run autoexec.bat (/d) and we want to run the command and move on, rather than leaving an interactive shell (/c "..."). Quoting is a funky problem, so we try for some 'standardised' behaviour (/s)
SET LASTLINE= - empty any current content of a LASTLINE environment variable
(...) & (...) - run everything before & and everything after & regardless of the exit code of the first bit. Use brackets as appropriate to group commands, where needed.
FOR /f "usebackq tokens=*" %L IN (`...`) DO ... - run the command string between backquotes (usebackq) and read all words (tokens=*) in each line of stdout (FOR /f) into a temporary variable %L.
DIR /b /s /-p dir1 dir2 dir3 dir3 dir2 dir1 "dir with space" - recursively (/s) enumerate through dir1, dir2, dir3 and dir with space, printing only the full path of files to stdout (/b). Don't require keypresses to page the output, if that has been set (/-p). Note that, due to foibles of FOR it is up to you to only quote directories with special chars (e.g. space), i.e. do not quote single-word names.
... ^| ... - pipe the stdout of the first command to the stdin of the second. We use ^ to escape | within the backquotes of FOR.
%SYSTEMROOT%\system32\find.exe /i "search_file_name" - find the string search_file_name in stdin. Use a case-insensitive search (/i).
%SYSTEMROOT%\system32\sort.exe - sort stdin and write to stdout.
DO #(...) - we need to run two commands for each line, so we group them in brackets. FOR normally prints each command before it runs it, the # suppresses this.
(IF /i NOT "{!LASTLINE!}"=="{%~L}" ECHO %~L) - if the line we are looking at %~L is not the same as the line we have stored !LASTLINE!, print the line we are looking at. Again, use a case-insensitive comparison (/i). We bookend both variables with {} to handle empty values, and we use delayed expansion (!LASTLINE! instead of %LASTLINE%) to expand LASTLINE every time it loops, not just when the FOR command is first seen.
SET "LASTLINE=%~L" - store the line we are looking at %~L into the variable LASTLINE.
If you do not have access to the inbuilt environment variables, you may not have %SYSTEMROOT% or %COMSPEC%. Substitute these for C:\Windows and C:\Windows\System32\cmd.exe or, more appropriately, determine the correct locations for the system you are scanning.
Download cygwin utility, it is simple Linux terminal under windows.
It allow to execute any Linux command in Windows.
And you have sort -u there.