Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/sql-server-2008/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 忽略文件中的第一行和最后一行_Powershell - Fatal编程技术网

Powershell 忽略文件中的第一行和最后一行

Powershell 忽略文件中的第一行和最后一行,powershell,Powershell,我正在尝试使用PowerShell替换多个文本文件的某些列中的字符。我有它工作得很好,除了我需要忽略每个文件中的第一行和最后一行,我不能让它工作 这就是我到目前为止所做的: $Location = "C:\Users\gerhardl\Documents\Tenacity\TEMP\POWERSHELL TESTS" $Data = "$Location\*.TXT" $Output = "$Location\Fixed" Get-Item $Data | ForEach-Object

我正在尝试使用PowerShell替换多个文本文件的某些列中的字符。我有它工作得很好,除了我需要忽略每个文件中的第一行和最后一行,我不能让它工作

这就是我到目前为止所做的:

$Location = "C:\Users\gerhardl\Documents\Tenacity\TEMP\POWERSHELL TESTS"
$Data = "$Location\*.TXT"
$Output = "$Location\Fixed"

Get-Item $Data |
    ForEach-Object {
        $file = $_
        $_ | 
            Get-Content | 
            ForEach-Object {
                $Beginning = $_.Substring(0,105)
                $Account = $_.Substring(105,20) -replace "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", " "
                $End = $_.Substring(125)
                '{0}{1}{2}' -f $Beginning,$Account,$End
            } |
            Set-Content -Path (Join-Path $Output  $file.Name)

    }

我知道也有类似的线程,但我的For Each循环似乎不能很好地处理这些建议。

跟踪第一行是可能的,可以对每个文件使用bool
$IsFirstLine=$True
,然后在ForEach对象内将其设置为false。但是,我认为,用管道方法跟踪最后一行是不可能的——在知道这是最后一行之前,您已经处理了最后一行

因此,您需要另一个循环来计算行数,或者需要一个缓冲区,以便在识别最后一行时能够撤消对它的更改

如果文件足够小,可以读入内存,您可以使用以下方法:

$Location = "C:\Users\gerhardl\Documents\Tenacity\TEMP\POWERSHELL TESTS"
$Data = "$Location\*.TXT"
$Output = "$Location\Fixed"

Get-Item $Data | ForEach-Object {                   # for each file..

    $Lines = @(Get-Content $_.FullName)             # read all the lines, force array.
    $LinesToProcess = $Lines[1..($Lines.Count - 1)] # get lines except first and last.

    $ProcessedLines = $LinesToProcess | ForEach-Object {    # for each line..

        $Beginning = $_.Substring(0,105)
        $Account = $_.Substring(105,20) -replace "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", " "
        $End = $_.Substring(125)
        '{0}{1}{2}' -f $Beginning,$Account,$End

    }

    $OutputLines = $Lines[0] + $ProcessedLines + $Lines[-1] # add original first and last

    $OutputLines | Set-Content -Path (Join-Path $Output $_.Name)

}

您可以使用
-Skip 1
-SkipLast 1

Get-Content $file  | Select-Object -Skip 1 | Select-Object -SkipLast 1
编辑PS<5:

$text = Get-Content $file | Select-Object -Skip 1
$newText = $text.GetRange(0,($text.Count - 1))
$newText

我设法做到了以下几点-不完全是我发布的内容,但无法做到这一点。第一行和最后一行(标题和尾部记录)的长度要短得多,因此我做了以下工作:

$Location = "C:\Users\gerhardl\Documents\Tenacity\TEMP\POWERSHELL TESTS"
$Data = "$Location\*.TXT"
$Output = "$Location\Fixed"

Get-Item $Data |
    ForEach-Object {
        $file = $_
        $_ | 
            Get-Content | 
            ForEach-Object {
            if ($_.length -gt 30)
            { 

                $Beginning = $_.Substring(0,105)
                $Account = $_.Substring(105,20) -replace "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", " "
                $End = $_.Substring(125)
                '{0}{1}{2}' -f $Beginning,$Account,$End
            }
            ELSE {
                $All = $_.Substring(0)
                '{0}' -f $All
                 }

            } |

            Set-Content -Path (Join-Path $Output  $file.Name)

    }
注意:这篇文章回答了一个一般性问题,即如何从处理中排除输入文件/输入集合的第一行和最后一行

在PSv5+中工作得很好(假设输出中应消除第一行和最后一行)

但是,他们的PSv4-solution无法工作(截至本文撰写时),因为
Get Content$file | Select Object-Skip 1
返回的数组(
[System.Object[]]
实例)没有
.GetRange()
方法。
下面是一个使用PowerShell的range操作符(
)的有效解决方案:

注:
*尝试
[1..-1]
很诱人,但在PowerShell中不起作用,因为
1..-1
的计算结果是下标
1,0,-1

*如果您知道至少有3个输入对象,则可以省略
[Math]::Max()
调用

但是,上述解决方案并不总是一个选项,因为它要求首先收集内存中的所有输入对象,这否定了基于管道的解决方案提供的逐个内存限制处理
(尽管内存中解决方案(如果可行)速度更快。)

要在PSv4-中解决此问题,您可以以管道友好的方式模拟
Select Object-SkipLast 1
,如下所示(
Select Object-Skip 1
-从一开始跳过-在PSv4-)中受支持

每个输入对象的输出延迟一次迭代,这实际上忽略了最后一次迭代

下面是对
-SkipLast
泛化,作为高级函数
跳过最后一个
实现,它使用实例延迟
对象的输出:

# Works in PSv2+
# In PSv5+, use `Select-Object -SkipLast <int>` instead.
Function Skip-Last {
  <#
  .SYNOPSIS
    Skips the last N input objects provided.
    N defaults to  1.
  #>
  [CmdletBinding()]
  param(
    [ValidateRange(1, 2147483647)] [int] $Count = 1,
    [Parameter(Mandatory = $True, ValueFromPipeline = $True)]$InputObject
  )

  begin { 
    $mustEnumerate = -not $MyInvocation.ExpectingInput # collection supplied via argument
    $qeuedObjs = New-Object System.Collections.Generic.Queue[object] $Count
  }
  process {
    # Note: $InputObject is either a single pipeline input object or, if
    #       the -InputObject *parameter* was used, the entire input collection.
    #       In the pipeline case we treat each object individually; in the
    #       parameter case we must enumerate the collection.
    foreach ($o in ((, $InputObject), $InputObject)[$mustEnumerate]) {
      if ($qeuedObjs.Count -eq $Count) {
        # Queue is full, output its 1st element.
        # The queue in essence delays output by $Count elements, which 
        # means that the *last* $Count elements never get emitted.
        $qeuedObjs.Dequeue()  
      }
      $qeuedObjs.Enqueue($o)
    }
  }
}

你想删除第一行和最后一行还是保持不变?我可以像你一样提前修改答案以包括我的代码吗?我正在努力使这项工作,但不能得到正确的-我是一个完全的新手与PS和我的技能,包括恶毒的其他脚本一起。。。请记住,我有单独的文本文件,需要写入相同的单独文件名;但是我已经把你的代码放进去了,并且做了一些调整。现在正在写文件,但是似乎已经删除了所有的换行符。哦;将
$OutputLines=$Lines[0]+
转换为
$OutputLines=@($Lines[0])+
v5解决方案很棒,但v4解决方案不起作用,因为
$text
是一个数组(
[System.Object[]]
),而数组没有
.GetRange()
方法。
# 'one', 'two', 'three' is a sample array. Output is 'one', 'two'
'one', 'two', 'three' | ForEach-Object { $notFirst = $False } { 
  if ($notFirst) { $prevObj }; $prevObj = $_; $notFirst = $True
}
# Works in PSv2+
# In PSv5+, use `Select-Object -SkipLast <int>` instead.
Function Skip-Last {
  <#
  .SYNOPSIS
    Skips the last N input objects provided.
    N defaults to  1.
  #>
  [CmdletBinding()]
  param(
    [ValidateRange(1, 2147483647)] [int] $Count = 1,
    [Parameter(Mandatory = $True, ValueFromPipeline = $True)]$InputObject
  )

  begin { 
    $mustEnumerate = -not $MyInvocation.ExpectingInput # collection supplied via argument
    $qeuedObjs = New-Object System.Collections.Generic.Queue[object] $Count
  }
  process {
    # Note: $InputObject is either a single pipeline input object or, if
    #       the -InputObject *parameter* was used, the entire input collection.
    #       In the pipeline case we treat each object individually; in the
    #       parameter case we must enumerate the collection.
    foreach ($o in ((, $InputObject), $InputObject)[$mustEnumerate]) {
      if ($qeuedObjs.Count -eq $Count) {
        # Queue is full, output its 1st element.
        # The queue in essence delays output by $Count elements, which 
        # means that the *last* $Count elements never get emitted.
        $qeuedObjs.Dequeue()  
      }
      $qeuedObjs.Enqueue($o)
    }
  }
}
PS> 'one', 'two', 'three', 'four', 'five' | Skip-Last 3
one
two