以正则表达式模式扩展变量不起作用

时间:2013-06-26 07:06:49

标签: regex variables powershell expansion

作为PowerShell编码的新手,我在PowerShell正则表达式模式中扩展变量时遇到了一些困难。

我想做的是:

  • 扫描两个时间范围内已更改的日志文件
  • 对于每个日志文件,我会得到一个名称的一部分,表示它引用的日期。

该日期存储在变量$filedate中。 然后去每行logfiles 每当我找到一条如下所示的行:

14:00:15 blablabla

在名为blabla20130620.log的文件中 我希望数据线变为

2013-06-20 14:00:15 blablabla

它应该将附加模式的输出写入文本文件(以连接不同的日志文件)

这是我到现在为止所做的事情(我现在正在沙盒中测试,所以没有评论等......)

$Logpath = "o:\Log"
$prevcheck="2013-06-24 19:27:14"
$currenttd="{0:yyyy-MM-dd HH:mm:ss}" -f (get-date)
$batch = 1000
[regex]$match_regex = '^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)'
If (Test-Path "$Logpath\test.txt"){
Remove-Item "$Logpath\test.txt"
}

$files=Get-ChildItem $LogPath\*.log | Where-Object { $_.LastWriteTime -ge "$prevcheck" -   and $_.LastWriteTime -le "$currenttd" -and !$_.PSIsContainer }
foreach ($file in $files)
{
$filedate=$file.Name.Substring(6,4) + "-" + $file.Name.Substring(10,2) + "-" +   $file.Name.Substring(12,2)

## This doesn't seem to work fine
## results look like:
## "$filedate" 14:00:15 blablabla

$replace_regex = '"$filedate" $_'

## I tried this too, but without success
## The time seems to dissappear now
## results look like:
## 2013-06-20  blablabla 

#$replace_regex = iex('$filedate' + $_)

(Get-Content $file.PSPath -ReadCount $batch) |
 foreach-object {if ($_ -match $match_regex) { $_ -replace $match_regex, $replace_regex}      else { $_ }}|
out-file -Append "o:\log\test.txt"

2 个答案:

答案 0 :(得分:1)

在PowerShell中,字符串必须是双引号(")才能进行变量替换。单引号(')字符串不执行变量替换。

在你的脚本中(我建议你缩进代码块的内容以使结构更容易理解):

$replace_regex = '"$filedate" $_'

其中字符串是单引号,因此没有变量替换。这可以通过记住反引号(`)字符来解决,该字符可用于转义双引号字符串中嵌入的双引号:

$replace_regex = "`"$filedate`" $_"

但请记住:

  • $是一个正则表达式元字符,因此如果您想在双引号中的正则表达式中包含$,则需要对其进行转义以避免PSH将其视为变量的开头名称
  • 变量中的任何正则表达式元字符都具有正则表达式的含义。考虑在替换之前转义变量的内容([regex]::Escape(string))。

答案 1 :(得分:0)

你的事情过于复杂。

  • 您正在比较Where-Object过滤器中的日期,因此您无需将参考日期转换为字符串。只需使用日期:

    $prevcheck = Get-Date "2013-06-24 19:27:14"
    $currenttd = Get-Date
    
  • 您可以使用正则表达式从文件名中提取日期并将其转换为所需的格式:

    $filedate = $file.BaseName -replace '^.*(\d{4})(\d{2})(\d{2})$', '$1-$2-$3'
    
  • 用于匹配时间的正则表达式过于正确。请改用^(\d{2}:\d{2}:\d{2})。它有点邋,,但它很可能就足够了,并且更容易看到它。

  • 要在日期前加上时间匹配,请使用"$filedate `$1"。双引号将导致$filedate从文件名扩展到日期,并且转义的$(``$ 1`)将保持分组匹配(请参阅Richard的说明)。

  • 虽然您可以将每个步骤的结果分配给变量,但使用单个管道更简单。

试试这个:

$Logpath   = "o:\Log"
$Logfile   = "$Logpath\test.txt"
$prevcheck = Get-Date "2013-06-24 19:27:14"
$currenttd = Get-Date

If (Test-Path -LiteralPath $Logfile) { Remove-Item $Logfile }

Get-ChildItem "$LogPath\*.log" | ? {
  -not $_.PSIsContainer -and
    $_.LastWriteTime -ge $prevcheck -and
    $_.LastWriteTime -le $currenttd
} | % {
  $filedate = $_.BaseName -replace '^.*(\d{4})(\d{2})(\d{2})$', '$1-$2-$3'
  Get-Content $_ | % {
    $_ -replace '^(\d{2}:\d{2}:\d{2})', "$filedate `$1"
  } | Out-File -Append $Logfile
}