Powershell - 基于静态数组删除多行文本?

时间:2013-12-16 23:14:48

标签: arrays powershell

编辑:2013年12月19日

我未能恰当地定义可能引起混淆的输入,对此感到抱歉。输入文件是IIS日志,格式化需要保持不变。这些字段看起来像这样; “字段:日期时间s-ip cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip cs(User-Agent)cs(Referer)sc-status sc-substatus sc-win32-状态时间“

网址GET会显示这样的内容;

2013-12-07 00:23:50 XXX.XXX.XXX.XXX POST / code = 5071 80 - XXX.XXX.XXX.XXX Mozilla / 4.0 +(兼容; + MSIE + 8.0; +的Windows NT + 5.1 + +三叉戟/ 4.0; + NET + CLR 2.0.50727 +; + NET + CLR + 3.0.4506.2152; + NET + CLR + 3.5.30729; + NET4.0C; + NET4 .0E)http://blah.blah.com/?code=5071 200 0 64 3478

“code = 5071”帮助我们识别网址,如果我们删除所有其他网址,我们就可以运行统计工具并查找有多少匹配等等。


当时,在编码方面我是一个全新的,所以随意嘲笑。我正在尝试获取一个日志文件并根据多个变量删除行,我想我可以创建一个数组,这样只需要删除或添加一个数字就可以编辑一个文件。输入文件是一个简单的日志,包含几个字段,其中一个是“ID”,所以类似于; ddmmyy blah blah ID。该ID是一个十位数字,其中有三十七个。目的是读取日志,去掉所有不匹配的ID,然后将结果输出到新的日志文件。

此代码工作正常,但似乎在停止之前我只能有大约十四个“ - 并且”

Get-Content .\combined.log | Where-Object{$_-NotMatch '10011250' -And $_-NotMatch '10005816' -And $_-NotMatch '5077'} |Set-Content combined1.log

我拖着网,学会尽可能多地处理数组,但似乎没有任何效果,我知道这是我以及我如何设置它。我觉得这样的事可能有用;

$a = @(10011250, 10005816, 14200712, 2418, 10005699, 5071, 10001040, 4814, 10025390, 4175, 10005940, 10000040, 10008181)
Get-Content .\combined.log | ForEach($i in $a) {Where-Object{$_-notcontains $a}}| Set-Content combined1.log

正如你所知,这远远不是我的专业领域。有什么建议吗?

3 个答案:

答案 0 :(得分:3)

您可以使用正则表达式中的替换在同一匹配操作中测试多个值。分隔多个值以匹配管道符号(|)。

Get-Content .\combined.log | Where-Object{$_-NotMatch '10011250|10005816'}

将过滤掉与10011250或10005816匹配的所有行 此外,-match运算符将立即匹配整个数组,并返回满足条件的成员。

试试这个:

$a = @(10011250, 10005816, 14200712, 2418, 10005699, 5071, 10001040, 4814, 10025390, 4175, 10005940, 10000040, 10008181)

$regex = [regex]($a -join '|')

Get-Content .\combined.log -ReadCount 1000 |
 foreach {$_ -notmatch $regex | Add-Content combined1.log}  

对于BACON:

$lines = (
'Line containing 10011250',
'Line containing 10005816',
'Line containing 10011250',
'Line containing 10915816'
 )

$lines -notmatch '10011250|10005816'

Line containing 10915816

答案 1 :(得分:0)

假设每一行以空白字符结尾,后跟整数ID,您可以使用:

$excludedIds = 10011250, 10005816, 14200712, 2418, 10005699, 5071, 10001040, `
    4814, 10025390, 4175, 10005940, 10000040, 10008181;
# Build a pattern from $excludedIds that matches one or more whitespace `
# characters followed by one of the above IDs followed by the end of the line
# Example: '\s+(10011250|10005816|14200712|...)$'
$excludedPattern = '\s+(' + ($excludedIds -join '|') + ')$';

Select-String -Path '.\combined.log' -Pattern $excludedPattern -NotMatch `
    | Select-Object -ExpandProperty 'Line' `
    | Set-Content -Path 'combined1.log';

Select-String cmdlet将为排除ID的每一行返回MatchInfo class的实例。我们使用Select-Object cmdlet检索Line property,代表每个MatchInfo的原始文本行。

请注意,我专门在该行的最后搜索整个ID。如果我没有这样做,我可能错误地匹配一个ID是另一个的子串。也就是说,以下一行......

161213 Field1 Field2 10915816

...匹配模式'915'但不匹配'\s+915$'(空格后跟字符串'915',后跟行尾)。这是我建议您仔细检查原始代码的行为,因为您可能会过滤掉部分但不完全匹配的ID,这可能是不可取的。

如果每行的第二个和第三个字段不包含任何空格,除了过滤之外,您还需要对每一行进行额外处理,这可能对您更有效:

$excludedIds = 10011250, 10005816, 14200712, 2418, 10005699, 5071, 10001040, `
    4814, 10025390, 4175, 10005940, 10000040, 10008181;
$records = Import-Csv -Delimiter ' ' -Header 'Date', 'Field1', 'Field2', 'ID' -Path '.\combined.log' `
    | Where-Object { $excludedIds -notcontains $_.ID; };
然后,

$records将包含已过滤的对象列表,每个对象都包含相应的DateField1Field2ID属性。不幸的是,原始的文本行现在丢失了,所以你必须自己重建它(或使用你想要的任何输出格式):

$records `
    | ForEach-Object { "$($_.Date) $($_.Field1) $($_.Field2) $($_.ID)"; } `
    | Set-Content -Path 'combined1.log';

答案 2 :(得分:0)

不要过度复杂化。

  • 获取文件内容
  • 针对数组中的每个项目检查每一行
  • 如果它通过了每个项目,请将其添加到新数组
  • 将新阵列输出到文件

没有控制台输出

$array = @(10011250, 10005816, 14200712, 2418, 10005699, 5071, 10001040, 4814, 10025390, 4175, 

10005940, 10000040, 10008181)

$file = ".\test.txt"
$log = Get-Content $file

ForEach ($line in $log) {
    ForEach ($item in $array) {
        if ($line -match "\b$($item)\b") {
            $good_lines += @($line)
        }
    }
}

$good_lines | Set-content ".\Combined1.log"

使用控制台输出

$array = @(10011250, 10005816, 14200712, 2418, 10005699, 5071, 10001040, 4814, 10025390, 4175, 

10005940, 10000040, 10008181)

$file = ".\test.txt"
$log = Get-Content $file

Write-Host "`n`n-- FILE LOADED: $((Get-Item $file).fullname)" -ForegroundColor "White"

ForEach ($line in $log) {
Write-Host "`n-- READING LINE: $line" -ForegroundColor "Yellow"
    ForEach ($item in $array) {
        sleep -milliseconds 100
        Write-Host "-- COMPARING: $item ..." -nonewline -ForegroundColor "Cyan"
        if ($line -match "\b$($item)\b") {
            Write-Host "MATCH" -ForegroundColor "Green"
            $good_lines += @($line)
        }
        else {
            Write-Host "NO MATCH" -ForegroundColor "Red"
        }
    }
}

$good_lines | Set-content ".\Combined1.log"