Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I search the first line and the last line in a text file?

I need to only search the 1st line and last line in a text file to find a "-" and remove it. How can I do it? I tried select-string, but I don't know to find the 1st and last line and only remove "-" from there.

Here is what the text file looks like:

 % 01-A247M15 G70 
N0001 G30 G17 X-100 Y-100 Z0
N0002 G31 G90 X100 Y100 Z45
N0003 ; --PART NO.:  NC-HON.PHX01.COVER-SHOE.DET-1000.050 
N0004 ; --TOOL:  8.55 X .3937 
N0005 ;  
N0006  % 01-A247M15 G70 

Something like this?

$1 = Get-Content C:\work\test\01.I

$1 | select-object -index 0, ($1.count-1)
like image 782
Blitzcrank Avatar asked Jan 18 '13 15:01

Blitzcrank


3 Answers

Ok, so after looking at this for a while, I decided there had to be a way to do this with a one liner. Here it is:

(gc "c:\myfile.txt") | % -Begin {$test = (gc "c:\myfile.txt" | select -first 1 -last 1)} -Process {if ( $_ -eq $test[0] -or $_ -eq $test[-1] ) { $_ -replace "-" } else { $_ }} | Set-Content "c:\myfile.txt"

Here is a breakdown of what this is doing:

First, the aliases for those now familiar. I only put them in because the command is long enough as it is, so this helps keep things manageable:

  1. gc means Get-Content
  2. % means Foreach
  3. $_ is for the current pipeline value (this isn't an alias, but I thought I would define it since you said you were new)

Ok, now here is what is happening in this:

  1. (gc "c:\myfile.txt") | --> Gets the content of c:\myfile.txt and sends it down the line
  2. % --> Does a foreach loop (goes through each item in the pipeline individually)
  3. -Begin {$test = (gc "c:\myfile.txt" | select -first 1 -last 1)} --> This is a begin block, it runs everything here before it goes onto the pipeline stuff. It is loading the first and last line of c:\myfile.txt into an array so we can check for first and last items
  4. -Process {if ( $_ -eq $test[0] -or $_ -eq $test[-1] ) --> This runs a check on each item in the pipeline, checking if it's the first or the last item in the file
  5. { $_ -replace "-" } else { $_ } --> if it's the first or last, it does the replacement, if it's not, it just leaves it alone
  6. | Set-Content "c:\myfile.txt" --> This puts the new values back into the file.

Please see the following sites for more information on each of these items:

Get-Content uses
Get-Content definition
Foreach
The Pipeline
Begin and Process part of the Foreach (this are usually for custom function, but they work in the foreach loop as well)
If ... else statements
Set-Content

So I was thinking about what if you wanted to do this to many files, or wanted to do this often. I decided to make a function that does what you are asking. Here is the function:

function Replace-FirstLast {
    [CmdletBinding()]
    param(
        [Parameter( `
            Position=0, `
            Mandatory=$true)]
        [String]$File,
        [Parameter( `
            Position=1, `
            Mandatory=$true)]
        [ValidateNotNull()]
        [regex]$Regex,
        [Parameter( `
            position=2, `
            Mandatory=$false)]
        [string]$ReplaceWith=""
    )

Begin {
    $lines = Get-Content $File
} #end begin 

Process {
    foreach ($line in $lines) {
        if ( $line -eq $lines[0]  ) {
            $lines[0] = $line -replace $Regex,$ReplaceWith 
        } #end if
        if ( $line -eq $lines[-1] ) {
            $lines[-1] = $line -replace $Regex,$ReplaceWith
        }
    } #end foreach
}#End process

end {
    $lines | Set-Content $File
}#end end

} #end function

This will create a command called Replace-FirstLast. It would be called like this:

Replace-FirstLast -File "C:\myfiles.txt" -Regex "-" -ReplaceWith "NewText"

The -Replacewith is optional, if it is blank it will just remove (default value of ""). The -Regex is looking for a regular expression to match your command. For information on placing this into your profile check this article

Please note: If you file is very large (several GBs), this isn't the best solution. This would cause the whole file to live in memory, which could potentially cause other issues.

like image 138
Nick Avatar answered Nov 16 '22 02:11

Nick


try:

$txt = get-content c:\myfile.txt
$txt[0] = $txt[0] -replace '-'
$txt[$txt.length - 1 ] = $txt[$txt.length - 1 ] -replace '-'
$txt | set-content c:\myfile.txt
like image 6
CB. Avatar answered Nov 16 '22 03:11

CB.


You can use the select-object cmdlet to help you with this, since get-content basically spits out a text file as one huge array.

Thus, you can do something like this

get-content "path_to_my_awesome_file" | select -first 1 -last 1

To remove the dash after that, you can use the -Replace switch to find the dash and remove it. This is better than using System.String.Replace(...) method because it can match regex statements and replace whole arrays of strings too!

That would look like:

# gc = Get-Content. The parens tell Powershell to do whatever's inside of it 
# then treat it like a variable.
(gc "path_to_my_awesome_file" | select -first 1 -last 1) -Replace '-',''
like image 1
Carlos Nunez Avatar answered Nov 16 '22 02:11

Carlos Nunez