I need to create a windows .bat file that:
finds HTTPPortNumber=#### in a file
adds 1 to ####
saves that HTTPPortNumber=NEWPORT to the file.
Basically I am trying to increment the port number in a config file by 1 and save it.
I have been playing with powershell eg:
powershell -Command "(Select-String "HTTPPortNumber=*" c:\Work\Clients\bcg\Config\Tm1s.cfg)"
But I can't figure out how to pipe the result into a variable so I can run substr on it.
You can find a sample cfg file here for testing.
Here is a beginning example, but you should give us more details to understand more your aim :
#echo off
setlocal enabledelayedexpansion
set "filename=c:\Work\Clients\bcg\Config\Tm1s.cfg"
for /f "usebackq tokens=2 delims==" %%i in (`findstr /r /c:"HTTPPortNumber=.*" %filename%`) do (
set "port=%%i"
set /a "newport=port+1"
set "newline=HTTPPortNumber=!newport!"
echo Found HTTPPortNumber=!port!. Incrementing to !newport!.
type %filename% | findstr /v /c:"HTTPPortNumber=.*" > tempfile.txt
echo !newline! >> tempfile.txt
move /y tempfile.txt %filename% > nul
)
echo Done.
pause
This script uses the findstr command to search for the line containing HTTPPortNumber= in the specified file.
The line is then processed using the for /f loop, where usebackq tokens=2 delims== is used to parse the line and extract the second token (the port number).
The port number is then incremented by 1 and saved back to the file by creating a temporary file with the updated line and then moving the temporary file back to the original file.
Edit : Powershell Solution
$filename = 'c:\Work\Clients\bcg\Config\Tm1s.cfg'
$fileContent = Get-Content $filename
$newContent = ''
foreach ($line in $fileContent) {
if ($line -match 'HTTPPortNumber=\d+') {
$port = [int] ($line -replace 'HTTPPortNumber=(\d+)', '$1')
$newport = $port + 1
Write-Output "Found HTTPPortNumber=$port. Incrementing to $newport."
$newContent += "HTTPPortNumber=$newport" + [Environment]::NewLine
} else {
$newContent += $line + [Environment]::NewLine
}
}
Set-Content $filename $newContent
Write-Output 'Done.'
This Powershell script will search for the line HTTPPortNumber=#### in the file c:\Work\Clients\bcg\Config\Tm1s.cfg and increment the value of #### by 1.
The updated value will be saved back to the same file.
Related
I want to extract a few thousands lines from a giant CSV file (~15GB, 6 million lines) from line number X to line number Y, without using a lot of RAM.
Using Powershell 2.0 from the command line interpreter, I was able to extract the first 2000 lines with:
PS> Get-Content -TotalCount 2000 file.csv > first_lines.csv,
and the last 2000 lines (skipping the first 5,998,000 ones), from the cmd.exe interpreter itself, with:
more +5998000 file.csv > last_lines.csv,
but now I want to extract, say, from line 3,000,001 to line 3,002,000, without having to create huge new files or put too much pressure on RAM.
Thanks in advance!
The -Index parameter to Select-Object can specify the range.
Get-Content -Path .\file.csv | Select-Object -Index (3000001..3002000)
Using variables makes it more flexible.
$x = 3000001
$y = 3002000
Get-Content -Path .\file.csv | Select-Object -Index ($x..$y)
What about the following batch-file:
rem // Initialise counter:
set /A "COUNT=0"
rem // Write to output file:
> "first_lines.csv" (
rem // Loop through lines beginning at a certain line number:
for /F usebackq^ skip^=5998000^ delims^=^ eol^= %%I in ("file.csv") do (
rem // This is an alternative way:
rem for /F delims^=^ eol^= %%I in ('more +5998000 "file.csv"') do (
rem // Return currently iterated line:
echo(%%I
rem // Increment counter:
set /A "COUNT+=1"
rem // Check counter state and conditionally terminate loop:
setlocal EnableDelayedExpansion
if !COUNT! geq 2000 goto :NEXT
endlocal
)
)
:NEXT
Regard that blank lines are skipped by for /F, and that lines are limited to about 8190 characters/bytes.
Here is my text file:
==================================================
Folder : D:\T\New folder
==================================================
==================================================
Folder : D:\T\Z-Ai
==================================================
==================================================
Folder : D:\T\Z-BiN
==================================================
I need to extract the paths from this file, so I have something like this:
D:\T\New folder
D:\T\Z-Ai
D:\T\Z-BiN
It seems I should use findstr TargetWord TargetFile.txt command. and Also it seems I can use regex like this: findstr /r "^[a-z][a-z]$ ^[a-z][a-z][a-z]$"
But I do not know how to loop through found targets or get the list of output. any help is really appreciated.
Based on your comment, you want to use the result to perform an xcopy task, it seems you really want something like this. Note I used example.txt as input file, and DESTINATION where you should add your destination, including the relevant xcopy switches you require:
#echo off
for /f "tokens=2*" %%i in ('type example.txt ^| findstr /i ":\\"') do xcopy "%%~j\*" DESTINATION
Alternatively we can use the findstr directly on Folder
#echo off
for /f "tokens=2*" %%i in ('type example.txt ^| findstr /i "Folder"') do xcopy "%%~j\*" DESTINATION
You can do like this :
#echo off
Title Extract list of path in a file using batch script
set "TxtList=MyList.txt"
Set "OutPutData=Output.txt"
Call :Extract "%TxtList%" "%OutPutData%"
Start "" "%OutPutData%"
Exit
::*****************************************************
:Extract <InputData> <OutPutData>
(
echo Data = WScript.StdIn.ReadAll
echo Data = Extract(Data,"[\w]:(\\[0-9\sA-Za-z\-]*)+"^)
echo WScript.StdOut.WriteLine Data
echo '************************************************
echo Function Extract(Data,Pattern^)
echo Dim oRE,oMatches,Match,Line
echo set oRE = New RegExp
echo oRE.IgnoreCase = True
echo oRE.Global = True
echo oRE.Pattern = Pattern
echo set oMatches = oRE.Execute(Data^)
echo If not isEmpty(oMatches^) then
echo For Each Match in oMatches
echo Line = Line ^& Trim(Match.Value^) ^& vbcrlf
echo Next
echo Extract = Line
echo End if
echo End Function
echo '************************************************
)>"%tmp%\%~n0.vbs"
cscript /nologo "%tmp%\%~n0.vbs" < "%~1" > "%~2"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
exit /b
::****************************************************
For Windows. you can use powershell.
select-string -Path c:\tmp\file.txt -Pattern '[A-Z]:(\\[0-9\ A-Za-z\-]*)+' -AllMatches | % { $_.Matches } | % { $_.Value }
In my opinion, For /F is all you need for the task. Although using Type may be useful in some situations, there's no need to use find.exe or findstr.exe for this task as you don't need to match a particular glob/pattern:
#For /F "EOL==Tokens=2*UseBackQ" %%A In ("TargetFile.txt")Do #"%__AppDir__%xcopy.exe" "%%B" "Destination\" /Options
Please note that it may be wise, if there's a chance that one or more of theses Folders do not exist, that you prepend using If Exist "%%B\". Importantly, if each of the lines containing the Folder paths, is space padded up to the end of its line, this solution will not work for you.
I have a script which can list all files under a folder and its subforlders, with some properties such as path, file name, modified date and size. But, I can't add one extra property, file owner.
#ECHO off
SET v1=%%~dpF
SET v2=%%~nxF
SET v3=%%~zF
(for /r %%F in (*) do #echo "%v1%","%v2%",%v3%) > test.csv
PAUSE
Basically I want to add a 4th parameter, which should show file owner. It is in Windows 7 environment.
You can use the dir command with the /q switch to include the owner of each file.
#ECHO OFF
SetLocal EnableDelayedExpansion
for /r %%a in (*) do for /f "tokens=5" %%b in ('dir /q "%%~fxa" ^| findstr "%%~nxa"') do (
echo "%%~dpa","%%~nxa","%%~za","%%b"
) >> test.csv
This will always append to test.csv, if you want to always recreate test.csv you can encase your entire for loop in parenthesis (as you had);
#ECHO OFF
SetLocal EnableDelayedExpansion
(for /r %%a in (*) do for /f "tokens=5" %%b in ('dir /q "%%~fxa" ^| findstr "%%~nxa"') do (
echo "%%~dpa","%%~nxa","%%~za","%%b"
)) > test.csv
Not exactly what you asked for, but I adapted a PowerScript to show what you ask for. Just update the PARAM section with your file and folder names, copy and paste into PowerShell and hit enter twice:
PARAM (
$Path = 'C:\Users\PATHHERE\',
$report = 'C:\Users\USERNAME\Desktop\OUTPUTFILENAMEHERE.csv'
)
$LastWrite = #{
Name = 'Last Write Time'
Expression = { $_.LastWriteTime.ToString('u') }
}
$Owner = #{
Name = 'File Owner'
Expression = { (Get-Acl $_.FullName).Owner }
}
$HostName = #{
Name = 'Host Name'
Expression = { $env:COMPUTERNAME }
}
Get-ChildItem -Recurse -Path $Path |
select $HostName, $Owner, Name, Directory, $LastWrite, Length |
Export-Csv -NoTypeInformation $Report
This script adapted from info found here. I find batch files to be more and more trouble to deal with these days, and PowerShell is very flexible. The guys over at serverfault.com will no doubt be able to help you better with these kinds of questions.
I am totally new on writing batch script,busy with the tutorials with the example below I can learn a thing or two.I really need help to write a batch script to insert a line of text at the middle of existing text file.
For example given the file myfile.txt with the contents:
a
bcd
efg
hjiklmnop
q
rs
t
uvwxyz
The the command ./put-in-middle.sh "=== === ===" myfile.txt
should modify the file to:
a
bcd
efg
hjiklmnop
=== === ===
q
rs
t
uvwxyz
#echo off
rem Count the number of lines in the file with FIND
for /F %%a in ('find /C /V "" ^< %2') do set numLines=%%a
rem Get the number of middle line
set /A middle=numLines/2
rem Process all lines, use FINDSTR /N to insert line numbers
for /F "tokens=1* delims=:" %%a in ('findstr /N "^" %2') do (
rem Echo the original line
echo/%%b
rem If the line is the middle one...
if %%a equ %middle% (
rem Insert the new line
echo %~1
)
)
Create previous Batch file as put-in-middle.bat and execute it this way:
put-in-middle "=== === ===" myfile.txt
Notes:
Previous program does not check for errors, like missing parameters. This checking may be added, if you wish.
The slash in the command echo/%%b is inserted to avoid the message "ECHO is on" if the line is empty. If the line may contain the string "/?", then the command should be changed to echo(%%b to avoid that the echo help be displayed in this case (the left parentheses is the only character that do that).
If the file contains Batch special characters, like < > | & ), the echo/%%b command fail. In this case, a special processing of files lines must be added. The same point apply to the new inserted line.
Previous program just display in the screen the new file. If you want to replace the original file, the output must be redirected to an auxiliary file and replace the original one at end:
.
(for /F "tokens=1* delims=:" %%a in ('findstr /N "^" %2') do (
. . .
)) > auxiliar.txt
move /Y auxiliar.txt %2
Using sed and assuming even number of lines:
sed $(( $(wc input -l | cut -d' ' -f1) / 2))'a=== === ===' input
And this is the script version put-in-middle.sh:
line=$1
file=$2
sed $(( $(wc $file -l | cut -d' ' -f1) / 2))"a$line" $file
I'm trying to combine two directories on a Windows 7 machine that have some of the same subfolders (but not all) and some of the same files (but not all). I'd like to copy
For example, I have the following directory structure and want to combine (copy or move) "Dir_A" and "Dir_Z". Where the file exists in the destination directory, I want to compare filesizes and keep the larger of the two files.
Dir A
Dir B
file 1.txt
file 2.txt
file 3.txt
Dir C
file 4.txt
Dir D
file 5.txt
file 6.txt
Dir_Z
Dir Y
file 8.txt
Dir C
file 4.txt
Dir D
file 6.txt
I'm comfortable using a cmd file or powershell. Thank you in advance.
EDIT: Modify to include spaces in the director and file names and add what I have so far.
Here's what I've been able to do so far. It appears to work with the exception of when there are spaces in the directory or filenames.
#echo off
echo :: Combine two folders, Keep the larger of any given files, Delete the other
if "%1"=="" goto :NoParam
if "%2"=="" goto :NoParam
setlocal enabledelayedexpansion
set SOURCE_DIR=%1
set DEST_DIR=%2
for /R "%SOURCE_DIR%" %%S in (*) do (
echo Source: "%%S"
#echo off
for /f "delims=" %%R in ('call MakeRelative.cmd "%%S" "%SOURCE_DIR%"') do (
set FILE_REL="%%R"
set filename=%DEST_DIR%\%%R
For %%D in ("!filename!") do (
Set Name=%%~nxD
if exist %DEST_DIR%\%%R (
echo File Exists
if %%~zD lss %%~zS (
echo Destination %%~zD is smaller than Source %%~zS
call robocopy %%~dpS %%~dpD "!Name!" /MOV
) else del %%S && Echo File is not larger, Deleting %%S
) else call robocopy %%~dpS %%~dpD "!Name!" /MOV
)
)
)
Pause
goto :eof
:NoParam
echo.
echo Syntax: %0 [Source_DIR] [Dest_DIR]
goto :eof
I make use of the MakeRelative.cmd as outlined here: http://www.dostips.com/DtCodeCmdLib.php#MakeRelative
I apologize that this is not elegant.
I'm not much of a PowerShell developer, but this should do the work and is hopefully somewhat more obvious regarding what it's doing than the batch file.
if($args.length -ne 3) {
"usage: PowerShell ThisScriptName.ps1 -command ""SourceDirectory"" ""DestinationDirectory""";
Exit
}
function CopyFileIfSourceIsLarger($SourceFile, $DestinationFile) {
$S = New-Object IO.FileInfo($SourceFile.ToString());
$D = New-Object IO.FileInfo($DestinationFile.ToString());
if ($S.Length -gt $D.Length ) {
"Overwriting smaller file " + $D.FullName;
[IO.File]::Copy($S.FullName, $D.FullName, $true);
}
}
$SourceDir = New-Object IO.DirectoryInfo($args[1]);
$DestinationDir = New-Object IO.DirectoryInfo($args[2]);
$SourceDirectoryPath = $SourceDir.FullName;
$DestinationDirectoryPath = $DestinationDir.FullName;
"Source Path: " + $SourceDirectoryPath;
"Destination Path: " + $DestinationDirectoryPath;
$SourceItems = Get-ChildItem -recurse $SourceDir;
"Synchronizing Directory Structure..."
foreach ($dir in $SourceItems | ? { $_ -is [IO.DirectoryInfo] }) {
$sourceRelative = $dir.fullname.Substring($SourceDirectoryPath.length + 1);
if ([IO.Directory]::Exists([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) -eq $false) {
"Creating folder " + [IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative);
[IO.Directory]::CreateDirectory([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) | out-null;
}
}
"Synchronizing Files..."
foreach ($file in $SourceItems | ? { $_ -is [IO.FileInfo] }) {
$sourceRelative = $file.fullname.Substring($SourceDirectoryPath.length + 1);
if ([IO.File]::Exists([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative)) -eq $true) {
CopyFileIfSourceIsLarger ([IO.Path]::Combine($SourceDirectoryPath,$sourceRelative).ToString()) ([IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative).ToString());
} else {
"Creating file " + [IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative);
[IO.File]::Copy([IO.Path]::Combine($SourceDirectoryPath,$sourceRelative).ToString(),[IO.Path]::Combine($DestinationDirectoryPath,$sourceRelative).ToString()) | out-null;
}
}
"All done."
#Thanks to:
#"Identifying Object Types": http://powershell.com/cs/blogs/tobias/archive/2008/10/14/identifying-object-types.aspx
#"Exiting early from foreach": http://stackoverflow.com/questions/10277994/powershell-how-to-exit-from-foreach-object
#"Calling functions with multiple parameters" http://stackoverflow.com/questions/4988226/powershell-multiple-function-parameters
When the script runs, files 1,2,3,5,9, and 10 get copied, and file 6 gets overwritten because it is smaller in the destination.
Here is a batch file that sets up your test case (plus some extra folders to test spaces in the names). I have commented out the two lines that clear out directories A and Z for safety but you can remove the REM statements if you are unconcerned about deleting files in a folder A and Z in the current directory.
#ECHO OFF
REM Uncomment at own risk RD /S /Q A
REM Uncomment at own risk RD /S /Q Z
MD "A\B"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 1.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 2.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\B\file 3.txt"
MD "A\C"
echo aaaaaaaabbbbbbbbcccccccc>"A\C\file 4.txt"
MD "A\D"
echo aaaaaaaabbbbbbbbcccccccc>"A\D\file 5.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\D\file 6.txt"
MD "A\FOLDER E"
echo aaaaaaaabbbbbbbbcccccccc>"A\FOLDER E\file 9.txt"
echo aaaaaaaabbbbbbbbcccccccc>"A\FOLDER E\file 10.txt"
MD "Z\Y"
echo aaaaaaaabbbbbbbbcccccccc>"Z\Y\file 8.txt"
MD "Z\C"
echo aaaaaaaabbbbbbbbccccccccdddddddd>"Z\C\file 4.txt"
MD "Z\D"
echo aaaaaaaa>"Z\D\file 6.txt"