6

我只需要搜索文本文件中的第一行和最后一行即可找到“-”并将其删除。我该怎么做?我尝试了选择字符串,但我不知道找到第一行和最后一行,只从那里删除“-”。

这是文本文件的样子:

 % 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)
4

8 回答 8

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
于 2013-01-18T15:58:56.353 回答
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. $_用于当前管道值(这不是别名,但我想我会定义它,因为你说你是新人)

好的,现在这是发生的事情:

  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" --> 这会将新值放回文件中。

有关这些项目的更多信息,请参阅以下网站:

Get-Content 使用
Get-Content 定义
Foreach Foreach
的 Pipeline
Begin 和 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正在寻找一个正则表达式来匹配您的命令。有关将其放入您的个人资料的信息,请查看本文

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

于 2013-01-18T17:45:22.993 回答
1

您可以使用select-objectcmdlet 来帮助您解决此问题,因为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 '-',''
于 2013-01-18T17:00:25.083 回答
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 是一种快速检查它是否存在的方法。

我希望它有所帮助。

于 2015-05-08T09:16:28.367 回答
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++ 
} 

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

于 2013-01-18T20:47:20.773 回答
0

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

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
}

看起来它现在运行良好。

于 2013-01-21T16:20:08.777 回答
0

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

获取内容 $file_txt | 选择对象 -last 1

于 2017-06-27T08:51:42.770 回答
0

我最近在 .bat 文件的最后一行中搜索注释。它似乎弄乱了以前命令的错误代码。我发现这对于在文件的最后一行中搜索模式很有用。Pspath 是 get-content 输出的隐藏属性。如果我使用选择字符串,我会丢失文件名。*.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

于 2020-03-27T18:51:02.273 回答