I need to remove last character in text file and set this content. First I have to find location the last character.
$dest= "K:\test.txt"
$count_characters= (Get-Content $dest | Measure-Object -Character).Characters
Now I know count of characters - the last one ($count_characters) I must remove and set content. Is it possible?
I would first access the last line using the array index -1. Then, You could use a simple regex which captures the whole line except the last chracter and replace it:
$dest= "K:\test.txt"
$replaceCharacter = 'A'
$content = Get-Content $dest
$content[-1] = $content[-1] -replace '^(.*).$', "`$1$replaceCharacter"
$content | Set-Content $dest
Related
I need to loop through multiple text files and check for a $ value in position 7 on each line of text and replace it with an * when found. But ONLY when it is in position 7. I do not want to change it if it is found in other positions. This is as far as I have gotten. Any help would be greatly appreciated.
Get-ChildItem 'C:\*.txt' -Recurse |
foreach $line in Get-Content $_ {
$linePosition1to5 = $line.Substring(0,6)
$linePosition7 = $line.Substring(6,1)
$linePositionRest = $line.Substring(8)
if($linePosition7 = "$"){
$linePosition7 = "*"
}
$linePosition1to5 + $linePosition7 + $linePositionRest |
Set-Content $_
}
Is there something that doesn't work in your example, or just that all the nested substrings are annoying to work with?
I'd use regex for this one. e.g.
$Lines = Get-Content -Path "C:\examplefile.txt" -raw
$Lines -replace '(?m)(^.{6})\$', '$1*'
To explain the regex:
?m indicates that it's multiline, required because I used raw get-content rather than pulling an array. Array would work too, just needs a loop like you did.
^.{6} line start plus any 6 characters (capture group 1)
$ escaped dollar character
$1* Capture group 1 left as is, dollar replaced with *, anything else not captured and therefore left untouched.
Thanks for code and the explanation. I realized that I left out the -raw option and it did work. Putting it back in it seems to add a line to the end of each file. Unless you can think of reason why I shouldn't I was going to leave it out.
Get-ChildItem 'C:\TEST\*.txt' -Recurse | ForEach {
(Get-Content $_ | ForEach { $_ -replace '(?m)(^.{6})\$', '$1*'}) |
Set-Content $_
}
I want to add some content to a file in a new line.
But add-content appends a string to last line if there is no new line symbol at the end.
E.g. if I want to add AAA string and if I have a file file1.txt
my last line(last cursor position here)
the result will be
my last lineAAA
On the other hand, if I use file2.txt
my last line
(last cursor position here)
the command will result in
my last line
AAA
So I need to check if the last line is empty or not. If it's not empty I will just add `n symbol to the string.
But if I run the commands
$lastLine = get-content $filename -Tail 1
if($lastLine.Length -ne 0) { ... }
it will always return me a length of not empty string even if my last line contains no symbols.
How can I check if my last line is empty ?
You could opt to start adding newlines to the file and for the first line to add do
$file = 'D:\Test\Blah.txt'
$firstLine = 'AAA'
Add-Content -Path $file -Value ("{0}`r`n{1}" -f (Get-Content -Path $file -Raw).TrimEnd(), $firstLine)
After that first line, you can simply keep using Add-Content which always appends an newline (unless you tell it not to do that with switch -NoNewline).
Seeing your comment, you can test the length of the last line like this:
$file = 'D:\Test\Blah.txt'
$lastLine = ((Get-Content -Path $file -Raw) -split '\r?\n')[-1]
# $lastLine.Length --> 0
if($lastLine.Length -ne 0) { ... }
The -Raw switch tells Get-Content to read the file as a whole in a single string. Split this string into separate lines with -split '\r?\n' and you'll get an array, including the last empty line
When you use "Get-Content -Tail 1", it will always recover the last "non empty" line.
# -----------------
# Your method returns the same line even if the file contains an empty line at the end of the file
# -----------------
$lastEmptyLine = Get-Content "test_EmptyLine.txt" -Tail 1
$lastNonEmptyLine = Get-Content "test_NonEmptyLine.txt" -Tail 1
($lastEmptyLine -match '(?<=\r\n)\z')
#False
($lastNonEmptyLine -match '(?<=\r\n)\z')
#False
So if you want to keep the "Test" method (and not simply use Add-Content) you could use the following method :
# -----------------
# This method can tell you if a file finishes by an empty line or not
# -----------------
$contentWithEmptyLine = [IO.File]::ReadAllText("test_EmptyLine.txt")
$contentWithoutEmptyLine = [IO.File]::ReadAllText("test_NonEmptyLine.txt")
($contentWithEmptyLine -match '(?<=\r\n)\z')
#True
($contentWithoutEmptyLine -match '(?<=\r\n)\z')
#False
# -----------------
# You can also use Get-Content with Raw option
# -----------------
$rawContentWithEmptyLine = Get-Content "test_EmptyLine.txt" -Raw
$rawContentWithoutEmptyLine = Get-Content "test_NonEmptyLine.txt" -Raw
($rawContentWithEmptyLine -match '(?<=\r\n)\z')
#True
($rawContentWithoutEmptyLine -match '(?<=\r\n)\z')
#False
-Raw Ignores newline characters and returns the entire contents of a file in one string with the newlines preserved. By default, newline
characters in a file are used as delimiters to separate the input into
an array of strings. This parameter was introduced in PowerShell 3.0.
References :
Get-Content (Microsoft.PowerShell.Management)
Check CRLF at the end of every file
about_Comparison_Operators - PowerShell
Regular expression - Wikipedia
I want to add text into specific line of txt file. I can't find any solution on internet.
This code adds text in further line (I want for example second line):
$test_out = "test"
$test_out | Add-Content "C:\tmp\test.txt"
If you want to add text to the end of a specific line, you can do it like this
$fileContent = Get-Content $filePath
$fileContent[$lineNumber-1] += $textToAdd
$fileContent | Set-Content $filePath
If you want to replace the text instead of adding, just remove the '+' sign.
You do of course have to set the variables
$filePath, $textToAdd and $lineNumber first.
Here a solution which reads the content of the file and access the line using the array index (-1). This example adds the line test and a line break to the second line.
$filePath = 'C:\tmp\test.txt'
$test_out = "test"
$fileContent = Get-Content -Path $filePath
$fileContent[1] = "{0}`r`n{1}" -f $test_out, $fileContent[1]
$fileContent | Set-Content $filePath
I have the following txt file.
[AppRemover]
Enable=0
[CleanWipe]
Enable=0
[RerunSetup]
Enable=0
How do I change the Enable=0 to Enable=1 under [CleanWipe] only?
Below is how I plan on using the code with my file.
$Path = C:\temp\file.txt
$File = Get-Content -Path $Path
# Code to update file
$File | Out-File $Path
You can use -replace to update the value if it is 0.
$Path = C:\temp\file.txt
(Get-Content $Path -Raw) -replace "(?<text>\[CleanWipe\]\r?\nEnable=)0",'${text}1' |
Set-Content $Path
Using a module that parses INI files will be the best solution though. I'd recommend trying PsIni.
Explanation:
The -Raw switch reads the file contents as a single string. This makes it easier to work with newline characters.
-replace performs a regex match and then replace. Below is the regex match breakdown.
(?<text>) is a named capture group. Anything matched within that capture group can be recalled in the replace string as '${text}'.
\[CleanWipe\] is a literal match of [CleanWipe] while escaping the [] characters with \.
\r? is optional carriage return
\n is the newline character
Enable= is a literal match
0 is a literal match
The replace string is the capture group contents and 1 when a match exists. Technically, a capture group is not needed if you want to use a positive lookbehind instead. The positive lookbehind assertion is (?<=). That solution would look like the following:
$Path = C:\temp\file.txt
(Get-Content $Path -Raw) -replace "(?<=\[CleanWipe\]\r?\nEnable=)0",'1' |
Set-Content $Path
The problem with the -replace solutions as they written is they will update the file regardless of a change actually being made to the contents. You would need to add an extra comparison to prevent that. Other issues could be extra white space on any of these lines. You can account for that by adding \s* where you think those possibilities may exist.
Alternative With More Steps:
$file = Get-Content $Path
$TargetIndex = $file.IndexOf('[CleanWipe]') + 1
if ($file[$TargetIndex] -match 'Enable=0') {
$file[$TargetIndex] = 'Enable=1'
$file | Set-Content $Path
}
This solution will only update the file if it meets the match condition. It uses the array method IndexOf() to determine where [CleanWipe] is. Then assumes the line you want to change is in the next index.
IndexOf() is not the only way to find an index. The method requires that your line match the string exactly. You can use Select-String (case-insensitive by default) to return a line number. Since it will be a line number and not an index (indexes start at 0 while line numbers start at 1), it will invariably be the index number you want.
$file = Get-Content $Path
$TargetIndex = ($file | Select-String -Pattern '[CleanWipe]' -SimpleMatch).LineNumber
if ($file[$TargetIndex] -match 'Enable=0') {
$file[$TargetIndex] = 'Enable=1'
$file | Set-Content $Path
}
I'm trying to write a script to find all the periods in the first 11 characters or last 147 characters of each line (lines are fixed width of 193, so I'm attempting to ignore characters 12 through 45).
First I want a script that will just find all the periods from the first or last part of each line, but then if I find them I would like to replace all periods with 0's, but ignore periods on the 12th through 45th line and leaving those in place. It would scan all the *.dat files in the directory and create period free copies in a subfolder. So far I have:
$data = get-content "*.dat"
foreach($line in $data)
{
$line.substring(0,12)
$line.substring(46,147)
}
Then I run this with > Output.txt then do a select-string Output.txt -pattern ".". As you can see I'm a long ways from my goal as presently my program is mashing all the files together, and I haven't figured out how to do any replacement yet.
Get-Item *.dat |
ForEach-Object {
$file = $_
$_ |
Get-Content |
ForEach-Object {
$beginning = $_.Substring(0,12) -replace '\.','0'
$middle = $_.Substring(12,44)
$end = $_.Substring(45,147) -replace '\.','0'
'{0}{1}{2}' -f $beginning,$middle,$end
} |
Set-Content -Path (Join-Path $OutputDir $file.Name)
}
You can use the powershell -replace operator to replace the "." with "0". Then use substring as you do to build up the three portions of the string you're interested in to get the updated string. This will output an updated line for each line of your input.
$data = get-content "*.dat"
foreach($line in $data)
{
($line.SubString(0,12) -replace "\.","0") + $line.SubString(13,34) + ($line.substring(46,147) -replace "\.","0")
}
Note that the -replace operator performs a regular expression match and the "." is a special regular expression character so you need to escape it with a "\".