如何搜索文本文件中的第一行和最后一行?

时间:2013-01-18 15:52:49

标签: powershell powershell-ise

我只需要搜索文本文件中的第一行和最后一行来查找“ - ”并将其删除。 我该怎么做? 我尝试了select-string,但我不知道找到第1行和最后一行,只从那里删除“ - ”。

以下是文本文件的样子:

 % 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 

这样的东西?

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

$1 | select-object -index 0, ($1.count-1)

8 个答案:

答案 0 :(得分:6)

尝试:

$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

答案 1 :(得分:6)

好的,所以看了一会儿之后,我觉得必须有一种方法可以用一个衬垫做到这一点。这是:

(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"

以下是对此做法的细分:

首先,那些现在熟悉的别名。我只是将它们放入,因为命令足够长,所以这有助于保持可管理性:

  1. gc表示Get-Content
  2. %表示Foreach
  3. $_用于当前管道值(这不是别名,但我认为我会定义它,因为你说你是新的)
  4. 好的,现在这里发生了什么:

    1. (gc "c:\myfile.txt") | - >获取c:\myfile.txt的内容并将其发送到行
    2. % - >是foreach循环(单独遍历管道中的每个项目)
    3. -Begin {$test = (gc "c:\myfile.txt" | select -first 1 -last 1)} - >这是一个开始块,它在进入管道之前运行所有内容。它将c:\myfile.txt的第一行和最后一行加载到一个数组中,以便我们检查第一个和最后一个项目
    4. -Process {if ( $_ -eq $test[0] -or $_ -eq $test[-1] ) - >这将检查管道中的每个项目,检查它是文件中的第一项还是最后一项
    5. { $_ -replace "-" } else { $_ } - >如果它是第一个或最后一个,它会进行替换,如果不是,它只是不管它
    6. | Set-Content "c:\myfile.txt" - >这会将新值放回文件中。
    7. 有关以下各项的详情,请参阅以下网站:

      Get-Content uses
      Get-Content definition
      Foreach
      The Pipeline
      Foreach的Begin and Process部分(这通常用于自定义功能,但它们也在foreach循环中工作)
      If ... else陈述 Set-Content

      所以我在思考如果你想对很多文件做这个,或者想经常这样做。我决定制作一个能满足你要求的功能。这是功能:

      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
      

      这将创建一个名为Replace-FirstLast的命令。会像这样调用:

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

      -Replacewith是可选的,如果它是空白,则只删除(默认值"")。 -Regex正在查找与您的命令匹配的正则表达式。有关将此信息放入个人资料的信息,请检查this article

      请注意:如果您的文件非常大(几GB),这不是最佳解决方案。这会导致整个文件存在于内存中,这可能会导致其他问题。

答案 2 :(得分:1)

您可以使用select-object cmdlet来帮助您解决此问题,因为get-content基本上将文本文件作为一个巨大的数组吐出。

因此,你可以做这样的事情

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

要在此之后删除短划线,您可以使用-Replace开关查找短划线并将其删除。这比使用System.String.Replace(...)方法更好,因为它可以匹配正则表达式语句并替换整个字符串数组!

这看起来像是:

# 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 '-',''

答案 3 :(得分:1)

如果您的文件非常大,您可能不想读取整个文件以获取最后一行。 gc -Tail将很快为您提供最后一行。

function GetFirstAndLastLine($path){

    return  New-Object PSObject -Property @{        
        First = Get-Content $path -TotalCount 1
        Last = Get-Content $path -Tail 1
        }
}

GetFirstAndLastLine "u_ex150417.log"

我在一个20 GB的日志文件上尝试了这个,它立即返回。读取文件需要数小时。

如果您想要保留所有删除内容并且只想从最后删除,您仍然需要阅读该文件。使用-Tail是检查它是否存在的快速方法。

我希望它有所帮助。

答案 4 :(得分:0)

更清晰的回答:

$Line_number_were_on = 0
$Awesome_file = Get-Content "path_to_ridiculously_excellent_file" | %{ 
    $Line = $_ 
    if ($Line_number_were_on -eq $Awesome_file.Length) 
         { $Line -Replace '-','' } 
    else 
         { $Line } ; 
    $Line_number_were_on++ 
} 

我喜欢单行,但我发现当我把简洁性放在功能上时,可读性往往会受到影响。如果您正在做的事情将成为其他人将阅读/维护的脚本的一部分,那么可读性可能需要考虑。

答案 5 :(得分:0)

按照Nick的回答:我确实需要对目录树中的所有文本文件执行此操作,这就是我现在正在使用的内容:

Get-ChildItem -Path "c:\work\test" -Filter *.i | where { !$_.PSIsContainer } | % { 
$txt = Get-Content $_.FullName; 
$txt[0] = $txt[0] -replace '-'; 
$txt[$txt.length - 1 ] = $txt[$txt.length - 1 ] -replace '-';
$txt | Set-Content $_.FullName
}

现在看起来它运作良好。

答案 6 :(得分:0)

简单过程: 将$ file.txt替换为您的文件名

  

Get-Content $ file_txt |选择对象-last 1

答案 7 :(得分:0)

我最近在.bat文件的最后一行中搜索注释。似乎弄乱了先前命令的错误代码。我发现这对于在文件的最后一行中搜索模式很有用。 Pspath是获取内容输出的隐藏属性。如果使用选择字符串,我将丢失文件名。 * .bat以-filter速度传递。

get-childitem -recurse . *.bat | get-content -tail 1 | where { $_ -match 'rem' } | 
  select pspath


PSPath
------
Microsoft.PowerShell.Core\FileSystem::C:\users\js\foo\file.bat

相关问题