Replace a character in all txt files - powershell

I'm looking to replace the character 'a' with 'o' in all txt files in a directory: "D:\Aither\Pca\Stat\"
For now I use this, but lose time because there are a lot of files.
(Get-Content D:\Aither\Pca\Stat\StrEtb.dat).replace('a', 'o') | Set-Content D:\Aither\Pca\Stat\StrEtb.dat
(Get-Content D:\Aither\Pca\Stat\StrEtb2.dat).replace('a', 'o') | Set-Content D:\Aither\Pca\Stat\StrEtb2.dat
....
I want something like this:
(Get-Content D:\Aither\Pca\Stat\*).replace('a', 'o') | Set-Content D:\Aither\Pca\Stat\*
Is this possible in PowerShell?

Using the -Filter and -File parameters, you will have better performance in collecting the files. Also, you can use a ForEach-Object to simply pipe these files through to the next cmdlet.
Because you are overwriting the file(s), you need to use brackets around Get-Content, so you are not trying to read and write to the same file at the same time.
Get-ChildItem -Path 'D:\Aither\Pca\Stat' -Filter '*.dat' -File -Recurse | ForEach-Object {
($_ | Get-Content).Replace('a', 'o') | Set-Content $_.FullName
}

Try this:
$collection = Get-ChildItem -Path 'D:\Aither\Pca\Stat' -Recurse -Filter '*.dat'
foreach( $file in $collection ) {
(Get-Content $file.FullName).replace('a', 'o') | Set-Content ($file.FullName) | Out-Null
}

Related

Powershell script to locate only files starting with specified letters and ending with .csv

cd 'A:\P\E\D'
$files = Get-ChildItem . *.CSV -rec
ForEach ($file in $files) {
(Get-Content $file -Raw) | ForEach-Object {
*some simple code*
} | Set-Content $file
}
How to modify this powershell script to locate only files starting with letters A/a to O/o and ending with .csv in specified directory cd?
I thought the solution below would work, but the test file M_K_O_X.CSV stored in the cd directory was not found and modified. The solution above will find and modify the file. It's possible that I have the regex expression wrong or the problem is somewhere else? I tried also this regex -- "[A-O]..CSV"
cd 'A:\P\E\D'
$files = Get-ChildItem . -rec | Where-Object { $_.Name -like "[a-oA-O]*.*.CSV" }
ForEach ($file in $files) {
(Get-Content $file -Raw) | ForEach-Object {
*some simple code*
} | Set-Content $file
}
Looking at your wildcard pattern, seems like you have an extra *. that shouldn't be there:
'M_K_O_X.CSV' -like '[a-oA-O]*.*.CSV' # False
'M_K_O_X.CSV' -like '[a-oA-O]*.CSV' # True
In this case you could simply use the -Include Parameter which supports character ranges. Also PowerShell is case insensitive by default, [a-oA-O]*.CSV can be reduced to [a-o]*.CSV:
Get-ChildItem 'A:\P\E\D' -Recurse -Include '[a-o]*.csv' | ForEach-Object {
($_ | Get-Content -Raw) | ForEach-Object {
# *some simple code*
} | Set-Content -LiteralPath $_.FullName
}
As commented, I would use the standard wildcard -Filter to filter for all files with a .csv extension.
Then pipe to a Where-Object clause in which you can use regex -match
$files = Get-ChildItem -Path 'A:\P\E\D' -Filter '*.csv' -File -Recurse |
Where-Object { $_.Name -match '^[a-o]' }
foreach ($file in $files) {
# switch `-Raw` makes Get-Content return a single multiline string, so no need for a loop
$content = Get-Content -Path $file.FullName -Raw
# *some simple code manipulating $content*
$content | Set-Content -Path $file.FullName
}
However, if these are valid csv files, I would not recommend using a pure textual manipulation on them, instead use Import-Csv -Path $file.FullName and work on the properties on each of the objects returned.

Replacing characters from multiple files with regex and Powershell

I would like to change _ to - in all .md files from folder FOO. The code below does what I need but I don't how to save results in folder FOO or some other...
$mdfiles = gci *.md
gc $mdfiles | ForEach-Object {if ( $_ -match '^!') {$_ -replace '_', '-'} else {$_}} | out-file ...
A ForEach-Object is needed to iterate over the file names as well. Ternary expressions are in PowerShell Core, but I am not sure about Windows PowerShell. This is not tested, but might give a start.
Get-ChildItem -File -Path '.' -Filter '*.md' |
ForEach-Object {
$OutFile = ".\foo\$($_.Name)"
Get-Content -Path $_.FullName |
ForEach-Object { ($_ -match '^!') ? ($_ -replace '_','-') : ($_) } |
Out-File -FilePath $OutFile
}
Also, it is bad practice to use alias commands in a stored script.

How to replace text in multiple file in many folder using powershell

I have many folder
ex: folder1,folder2,folder3... about folder100
In those folder have many files
ex: 1.html,2.html,3.html,4.html...about 20.html
I want to replace some text in those all html file in all folder
but not all text i want to replace is same.
ex:(for 1.html, i want to replace ./1_files/style.css to style.css) and (for 2.html, i want to replace ./2_files/style.css to style.css)....
So i try something like this and it work well
Get-ChildItem "*\1.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './1_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\2.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './2_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\3.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './3_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\4.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './4_files/style.css', 'style.css' | Set-Content $_
}
but i have to write many of those code "\4.html" "\5.html" "*\6.html" ...
i try this but it do not work
Do {
$val++
Write-Host $val
$Fn = "$val.html"
Get-ChildItem "*\$Fn" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './$val_files/style.css', 'style.css' |
Set-Content $_
}
} while($val -ne 100)
Please show me correct way to do..loop replace
thanks you
Assuming all your subfolders can be found inside one source folder path, you can do below to do the replacement in all those files:
# the path where all subfolders and html files can be found
$sourcePath = 'X:\Wherever\Your\Subfolders\Are\That\Contain\The\Html\Files'
Get-ChildItem -Path $sourcePath -Filter '*.html' -Recurse -File |
# filter on html files that have a numeric basename
Where-Object {$_.BaseName -match '(\d+)'} | ForEach-Object {
# construct the string to repace and escape the regex special characters
$replace = [regex]::Escape(('./{0}_files/style.css' -f $matches[1]))
# get the content as one single multiline string so -replace works faster
(Get-Content -Path $_.FullName -Raw) -replace $replace, 'style.css' |
Set-Content -Path $_.FullName
}

Add header to multiple CSV files

I'm looking for a way to add a header line into multiple CSV files.
Problem with this code below is that it will add an extra empty row at the end of each file. I don't understand why there is extra empty line but I need to delete those lines.
$header="Column1,Column2,Column3,Column4,Column5,Column6"
Get-ChildItem .\ -Recurse -Filter *.csv| Foreach-Object {
$header+"`r`n"+ (Get-Content $_.FullName | Out-String) |
Set-Content -Path $_.FullName
}
The canonical way would be to import the files specifying the headers and then re-export them:
$header = 'Column1', 'Column2', 'Column3', 'Column4', 'Column5', 'Column6'
Get-ChildItem .\ -Recurse -Filter '*.csv' | ForEach-Object {
$file = $_.FullName
(Import-Csv -Path $file -Header $header) | Export-Csv -Path $file -NoType
}
Export-Csv does add double quotes around all fields of the CSV, though. Also, parsing the data into objects does have a performance impact. If you don't want the double quotes added or are pressed for performance the solution suggested by #PetSerAl in the comments to your question might be a better approach for you:
$header = 'Column1,Column2,Column3,Column4,Column5,Column6'
Get-ChildItem .\ -Recurse -Filter '*.csv' | ForEach-Object {
$file = $_.FullName
#($header; Get-Content -Path $file) | Set-Content -Path $file
}

Read all files, change content, save again

I'm trying to do a replace in content of all files in a certain directory structure.
get-childItem temp\*.* -recurse |
get-content |
foreach-object {$_.replace($stringToFind1, $stringToPlace1)} |
set-content [original filename]
Can I get the filename from the original get-childItem to use it in the set-content?
Add processing for each file:
get-childItem *.* -recurse | % `
{
$filepath = $_.FullName;
(get-content $filepath) |
% { $_ -replace $stringToFind1, $stringToPlace1 } |
set-content $filepath -Force
}
Key points:
$filepath = $_.FullName; — get path to file
(get-content $filepath) — get content and close file
set-content $filepath -Force — save modified content
You can simply use $_, but you need a foreach-object around each file, too. While #akim's answer will work, the use of $filepath is unnecessary:
gci temp\*.* -recurse | foreach-object { (Get-Content $_) | ForEach-Object { $_ -replace $stringToFind1, $stringToPlace1 } | Set-Content $_ }