In a batch file I need to change, within a file, all instances of ##token## (just my own placeholder) with the value of a variable from earlier in the script (%tokenvar%), and output the result to a file. From an answer on here I came up with calling powershell:
type file.json|powershell -Command "$input|ForEach-Object{ $_ -replace \"##token##\", \"%tokenvar%\" }" > file.2.json
The problem is that the resultant file is wrapped at 80 chars which I need it not to be!
How can I do this?
You don't need to use Out-String in this case as Out-File has a Width parameter as well:
... | Out-File File.2.json -Width 300"
Just make sure the | Out-File ... is part of the PowerShell command.
The problem is that the redirection operator in PowerShell (>) will turn into Out-File with a width of 80 characters. You can use Out-File with an arbitrarily large width (I prefer 10k), or pipe to Set-Content (which will be slower). You can also assign the result into a variable, and use [IO.File]::WriteAllText to perform the update.
You can do that directly in your Batch file with no need of Powershell:
#echo off
setlocal DisableDelayedExpansion
for /F "delims=" %%a in (file.json) do (
set "line=%%a"
setlocal EnableDelayedExpansion
echo !line:##token##=%tokenvar%!
endlocal
)
This Batch file assume that there is not empty lines in file.json and that the value of %tokenvar% have not special Batch characters. These two points may be fixed, if needed.
Related
I have a list of file names present inside a file called My_text.txt, may be more than 100. I want to retrieve the Date modified, basically the DIR command output for all those file names.
My_Text.txt contains
D:\Users\dsa99_p\Desktop\My_Program1.txt
D:\Users\dsa99_p\Desktop\My_Program2.txt
D:\Users\dsa99_p\Desktop\My_Program3.txt
D:\Users\dsa99_p\Desktop\My_Program4.txt
and so on..
I want to retrieve the Date modified for all these My_Program1, My_Program2, My_Program3, My_Program4 files. How to do it? Please help.
If it's possible over Powershell then let me know.
In PowerShell the file content can be loaded by Get-Content and file information can be obtained with Get-ChildItem. So this is how it can be done in PowerShell:
Get-Content My_text.txt | ForEach-Object { (Get-ChildItem $_).LastWriteTime }
(Get-ChildItem (Get-Content My_text.txt)).LastWriteTime
Both commands do the same thing. Shorter form of them:
gc My_text.txt |% { (ls $_).LastWriteTime }
(ls (gc My_text.txt)).LastWriteTime
If you want a batch file solution
FOR /F "usebackq delims=" %%G IN ("My_Text.txt") DO ECHO FileName:%%G Modified:%%~tG
Because it is possible that one or more of the files may not exist, I would probably structure my code a little differently. I would first check whether each line related to an existing file, and only then get its information.
The first example I'll provide is for PowerShell, whilst it may seem like more text, it will be far more configurable, especially with regards to modifying the layout and content of the results.
powershell command line:
(Get-Content -Path '.\My_Text.txt') | ForEach-Object { If (Test-Path -LiteralPath $_ -PathType Leaf) { Get-Item -LiteralPath $_ | Select-Object -Property LastWriteTime, Name } }
cmd command line:
For /F "UseBackQ Delims=" %G In (".\My_Text.txt") Do #If "%~aG" Lss "d" If "%~aG" GEq "-" Echo %~tG: %~nxG
Single line batch-file version:
#(For /F "UseBackQ Delims=" %%G In (".\My_Text.txt") Do #If "%%~aG" Lss "d" If "%%~aG" GEq "-" Echo %%~tG: %%~nxG)&Pause
In all examples above, I have assumed that My_Text.txt is in the current directory, if it isn't please change its currently relative location .\ as necessary without modifying its quoting.
can you show me a way to solve following problem with Powershell or CMD?
This is my file names in folder.
002.mp3
003.mp3
.
.
.
604.mp3
I want to change that numbers to;
001.mp3
002.mp3
003.mp3
.
.
.
603.mp3
But important thing is, it has to be like that
002.mp3 to 001.mp3
003.mp3 to 002.mp3
...
...
...
604.mp3 to 603.mp3
thank you very much.
You can do the following:
$files = Get-ChildItem -Path "C:\PathToMP3Files\[0-6][0-9][0-9].mp3" -File
$files | Rename-Item -NewName {"{0:D3}.mp3" -f ([int]$_.BaseName - 1)} -whatif
Just remove the -whatif parameter to perform the rename if you are satisfied with the results.
Explanation:
The -Path parameter of Get-ChildItem supports wildcards. Using a wildcard range [0-6] (one character from the set 0 to 6), you can narrow down your target items.
Since New-Item's -NewName supports delay-script binding, you can pipe your FileInfo objects directly into the command. The -NewName parameter manipulates the Name property of the object. The code above is using BaseName, which is the Name without the extension, because it is an easy way to perform digit increase.
-f is the string format operator. It performs a substitution of {number} values within a string. The number corresponds to an item's index in the collection provided to the right of the -f.
This is simpler in a Batch file, and run faster than PS too! (just try it)
#echo off
setlocal EnableDelayedExpansion
for /F %%a in ('dir /B *.mp3') do set /A "n=1%%~Na-1" & ren "%%a" "!n:~1!.mp3"
Yoy may even do it directly at the command prompt with no need of a .bat file; just be sure that n variable does not exists (executing set "n=" before):
for /F %a in ('dir /B *.mp3') do #set /A "n=1%~Na-1" & call ren "%a" "%n:~1%.mp3"
So I have files (mostly documents) with a file name beginning with "YYYYMMDD - Title of file.etc"
I'm wanting to change the date format to YYYY-MM-DD
I'm wanting to do a script to batch rename since I'll be doing this every now and then.
My bat code so far after a 2 days of research to no avail:
for %%a in ("*.*") do ren *.* ????-??-??*.*
pause
Any help or point to the right direction for me to look at would be really helpful. Thanks
final
rem // Loop through all matching files:
for /F "eol=| delims=" %%F in ('
dir /B /A:-D-H-S "*.*"
') do (
rem // Store the current file name and extension to variables:
set "NAME=%%~F"
rem // Enable delayed expansion to avoid trouble with `!`:
setlocal EnableDelayedExpansion
rem // Rename file by applying sub-string expansion:
ren "!NAME!" "!NAME:~,4!-!NAME:~4,2!-!NAME:~6!!EXT!"
endlocal
)
pause
You are utilising a for loop but not using its meta-variable %%a in the body then, which makes no sense.
Unfortunately, you cannot just use ren for that, because every ? in the new name represents the character of the old name at that position.
I would do it the following way:
rem // First change to the target directory:
cd /D "D:\Target\Dir"
rem // Loop through all matching files:
for /F "eol=| delims=" %%F in ('
dir /B /A:-D-H-S "*.*" ^| findstr /I "^[1-2][0-9][0-9][0-9][0-1][0-9][0-3][0-9]"
') do (
rem // Store the current file name and extension to variables:
set "NAME=%%~nF" & set "EXT=%%~xF"
rem // Enable delayed expansion to avoid trouble with `!`:
setlocal EnableDelayedExpansion
rem // Rename file by applying sub-string expansion:
ren "!NAME!!EXT!" "!NAME:~,4!-!NAME:~4,2!-!NAME:~6!!EXT!"
endlocal
)
The [findstr][cmdfnd] is used here to filter for file names that begin with eight decimal digits that could represent a date. If you do not want that simply remove everything from ^| findstr up to the end of that line.
Delayed variable expansion is needed here, because you are writing and reading variables within the same block of code. Splitting the original name at fixed character positions is done by sub-string expansion.
(How-To: Extract part of a variable (substring))
[cmdfnd]: https://ss64.com/nt/findstr.html
(FINDSTR)
RightHanded,
Maybe you should look at Powershell commands.
The following powershell command replaces spaces with underscores of all files of the current directory :
dir | rename-item -NewName {$_.name -replace " ","_"}
Source : https://www.howtogeek.com/111859/how-to-batch-rename-files-in-windows-4-ways-to-rename-multiple-files/
You can see how to modify Powershell strings here for example : https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convert-string?view=powershell-5.1
Powershell will be much easier to do this. Use this:
#echo off
pushd "The Directory"
powershell -command "& {get-childitem | foreach {$NewName = $_.Name -replace '\d{8}.*', '\d{4}-\d{2}-\d{2}.*'; rename-item -path '.\$_.Name' -newname '$NewName'}}"
popd
goto :eof
You can use this as a function to rename the files to the format you want. You can call this function inside a loop FOR, if you want.
set old_filename=YYYYMMDD - Title of file.etc
:: Extract only the first 4 characters
SET yyyy=%old_filename:~0,4%
:: Skip 4 characters and then extract the next 2
SET mm=%old_filename:~4,2%
:: Skip 6 characters and then extract the next 2
SET dd=%old_filename:~6,2%
:: Skip 8 characters and then extract everything else
SET everything_else=%old_filename:~8%
:: Rename de old filename to the new
rename "%old_filename%" "%yyyy%-%mm%-%dd%%everything_else%"
So I'm making a batch script and I need to run a powershell command inside a for but it's running really slow, I don't know how to make it more efficient, I'm very new in this stuff. Here's part of my code:
for /f "tokens=*" %%G in (myfile.txt) do (
powershell -command '%%G' -replace ',+', ' ' >> newfile.txt
)
Since you say you are new to this. It's really important you get some ramp up on the topic. Using either all the free stuff Microsoft offers (Microsoft Virtual Academy or MS Channel9 or TechNet Virtual Labs or labsondemand), or youtube or at minimum review the help files first. There are lots of free eBooks as well and step by step blogs.
As the others have said, why not just do this in PS directly, to read and process the file. Though you don't have to, you can call a .ps1 from a .bat/.cmd/.vbs, etc., but you don't have to use it to process what PS can do.
# Giving a target file to be modified
# Check what is in the file
# Note: I am using Get-Content here, but if you have a .csv, then use the *csv* cmdlets
Get-Content -Path 'd:\temp\myfile.txt'
# Results
LIC,+CLIENT
12345,+Client1
54321,+Client2
34251,+Client3
# Test new file path
Test-Path -Path 'd:\temp\newfile.txt'
# Results
False
# Decide what to replace, code the replace
# and see what the new file content will look like when replaced
Get-Content -Path 'd:\temp\myfile.txt' |
ForEach{$_ -replace '\,\+',' '}
# Results
LIC CLIENT
12345 Client1
54321 Client2
34251 Client3
# Modify to send to a new file.
Get-Content -Path 'd:\temp\myfile.txt' |
ForEach{
$_ -replace '\,\+',' ' |
Out-File -FilePath 'D:\Temp\newfile.txt' -Append
}
# Results
Test-Path -Path 'd:\temp\newfile.txt'
True
Get-Content -Path 'd:\temp\newfile.txt'
# Results, should be the same as screen output.
LIC CLIENT
12345 Client1
54321 Client2
34251 Client3
Since you mentioned in your comment that you were trying to do it all in a batch script here is the basic syntax for string replacement. You have to first assign the FOR variable to an environmental variable before you can do any string replacement. You would also need to enable delayed expansion because you are manipulating a variable inside a parentheses code block.
#echo off
setlocal enabledelayedexpansion
(for /f "delims=" %%G in (myfile.txt) do (
set "line=%%G"
echo !line:+= !
)
)>newfile.txt
You could also do this without delayed expansion by using CALL ECHO
#echo off
(for /f "delims=" %%G in (myfile.txt) do (
set "line=%%G"
CALL echo %%line:+= %%
)
)>newfile.txt
I received a good suggestion in another thread to support the removal/replacement of specific characters from filenames in a directory structure. Works as expected for common ascii characters (like &).
PowerShell (works fine to remove & character from filenames):
powershell.exe -c "Get-ChildItem 'c:\Media\Downloads' -Filter '*&*' -Recurse | Rename-Item -NewName {$_.name -replace '&','' }"
I also need remove single quotes from some files: Example: mark's_file.txt.
I've tried a few variants without success. I think I am running into a punctuation issue I am unable sort out. I also tried using a variable = char(39) and adding to the string. No luck.
Any ideas to accomplish?
Note: Would like a self contained batch file approach, vs calling an external .ps1 file.
A Batch file also works fine to remove both & and ' characters from filenames:
#echo off
setlocal EnableDelayedExpansion
rem Remove "&" characters:
for /R "c:\Media\Downloads" %%a in ("*&*") do (
set "fileName=%%~NXa"
ren "%%a" "!filename:&=!"
)
rem Remove "'" characters:
for /R "c:\Media\Downloads" %%a in ("*'*") do (
set "fileName=%%~NXa"
ren "%%a" "!filename:'=!"
)
... but the Batch file start run much faster than the PS one!