1

我有一个 linux 服务器,它将全天生成几个需要插入数据库的文件;使用 Putty,我可以将它们 sftp 到运行 SQL 2008 的服务器。问题是文件本身的结构,它有一个要放在不同列中的文本字符串,但是在 sql 中批量插入会尝试将其全部放入到一列而不是六列。Powershell 可能不是最好的方法,但我在几个网站上看到它如何查找和替换或附加到行尾,它可以计数和插入吗?

所以文件看起来是这样的:'18240087A +17135555555 3333333333',其中18、24、00、87、A是不同的列,那么A和+之间有一个空格,即字符数10-19即另一列,然后字符 20-30 是一列,字符 31-36 是一个空格,它是新列,依此类推。所以我想插入一个'|' 或“,”,以便 sql 了解列的结束位置。PowerShell可以随机计数吗?


这可能不是回应所有回答的人的方式,我提前道歉。由于这是我的第一个 PowerShell 脚本,我感谢你们每个人的意见。这是生成 CDR 记录的 Avaya SIP 服务器,我必须从服务器中提取这些记录并将其插入 SQL 以供以后报告。导出的文件如下所示:

10/15 18:47

18470214A +14434444444 3013777777 CME-SBC HHHH-CM 4 M00 0

起初我只是想删除第一行并针对输出运行一个脚本,这是我从 Kieranties 帖子中修改的:

$test = 获取内容 C:\Share\CDR\testCDR.txt

$pattern = "^(.{2})(.{2})(.{1})(.{2})(.{1})(.{1})\s*(.{15}) (.{10})\s*(.{7})\s*(.{7})\s*(.{1})\s*(.{1})(.{1})(. {1})\s*(.*)$"

if($test -match $pattern){ $result = $matches.Values | 选择 -first ($matches.Count-1)

[array]::Reverse($result, 0, $result.Length)

$result = $result -join "|"    
$result | Out-File c:\Share\CDR\results1.txt

}

但后来我意识到我需要第一行,因为它包含日期。不过,我可以尝试以另一种方式解决这个问题。

我现在还看到有时文件包含 2 行或更多行 CDR 信息,例如:

10/15 18:24

18240087A +14434444444 3013777777 CME-SBC HRSA-CM 4 M00 0

18240096A +14434444445 3013777778 CME-SBC HRSA-CM 4 M00 0

而我制作的 .ps1 文件没有给出第二个字符串,所以我尝试添加:

foreach ($test 中的$Data) { $Data = $Data -split(',')

它无法运行。我怎样才能做多行(可能还有第一行)?如果您知道可以提供帮助的教程,那也将不胜感激!

4

4 回答 4

1

PowerShell 是一个我喜欢的很棒的工具,它可以做很多事情。我看到您使用的是 SQL Server 2008。根据您在服务器上运行的 SQL Server 的版本,它很可能具有 SQL Server Integration Services (SSIS),这是一个提取、转换和加载 (ETL) 工具帮助在许多情况下迁移数据,例如您的情况。您在此处描述的文件听起来像一个固定宽度的文件,SSIS 可以轻松处理和导入该文件,如果这是一个经常性需求(听起来像),SQL Server 有很好的方法来自动加载,包括 sftp 任务的自动化,甚至运行 PowerShell 脚本作为 ETL 的一部分(我已经做过几次)。

如果您的文件确实是固定宽度并且您想使用 PowerShell 将其转换为分隔文件,那么您在答案中使用的正则表达式方法效果很好,或者有几种方法使用 System.String 方法,例如 .insert()允许您在行中使用字符索引插入分隔符(使用 Get-Content 读取文件并每行创建一个 String 对象,然后使用 Foreach 循环或 Foreach-Object 和管道循环遍历它们)。一个稍微困难的方法是使用 .Substring() 方法。您可以使用 Substring 构建新的 String 行以提取每一列并将这些值与分隔符连接起来。对于刚接触 PowerShell 的人来说,这可能很多,但学习和熟练掌握它的最佳方法之一是练习以多种方式编写相同的脚本。

于 2015-06-10T15:54:43.253 回答
0

我已经根据您的回复改进了我的答案(请注意,您最好更新您的实际问题以包含该信息!)

Powershell的Get-Content好处在于它将内容作为在行尾字符上拆分的数组返回。再加上允许从数组中进行多次赋值,你最终会得到一些简洁的代码。

以下具有根据您对我的原始答案的修改版本处理每一行的功能。然后它由处理文件的函数包装。

这会读取给定的文件,将第一行设置为$date,其余内容设置为$content. 然后它创建一个输出文件,将日期添加到输出中,然后循环执行正则表达式检查的其余内容,如果检查成功,则添加内容的解析版本。

Function Parse-CDRFileLine {
    Param(
        [string]$line
    )

    $pattern = "^(.{2})(.{2})(.{1})(.{2})(.{1})(.{1})\s*(.{15})(.{10})\s*(.{7})\s*(.{7})\s*(.{1})\s*(.{1})(.{1})(.{1})\s*(.*)$"
    if($line -match $pattern){ 
        $result = $matches.Values | select -first ($matches.Count-1)
        [array]::Reverse($result, 0, $result.Length)
        $result = $result -join "|"    
        $result
    }
}



Function Parse-CDRFile{
    Param(
        [string]$filepath
    )    

    # Read content, setting first line to $date, the rest to $content
    $date,$content = Get-Content $filepath    

    # Create the output file, overwrite if neccessary
    $outputFile = New-Item "$filepath.out" -ItemType file -Force

    # Add the date line
    Set-Content $outputFile $date

    # Process the rest of the content
    $content | 
        ? { -not([string]::IsNullOrEmpty($_)) } |
        % { Add-Content $outputFile (Parse-CDRFileLine $_) }
}

Parse-CDRFile "C:\input.txt"

我使用了您的示例输入,得到的结果是:

18:24 10/15
18|24|0|08|7|A|+14434444444 30|13777777 C|ME-SBC |HRSA-CM|4|M|0|0|0
18|24|0|09|6|A|+14434444445 30|13777778 C|ME-SBC |HRSA-CM|4|M|0|0|0

那里有大量的资源,但我特别建议的是 Douglas Finkes Powershell for Developers它简短、简洁且包含大量重要信息,可让您以正确的心态思考 Powershell

于 2012-10-16T14:22:27.433 回答
0

This is a way (really ugly IMO, I think it can better done):

$a = '18240087A +17135555555 3333333333'
$b = @( ($a[0..1] -join ''), ($a[2..3] -join ''), ($a[4..5] -join ''),
    ($a[6..7] -join ''), ($a[8] -join ''), ($A[10..19] -join ''),
    ($a[20..30] -join ''), ($a[31..36] -join ''))
$c = $b -join '|'
$c
18|24|00|87|A|+171355555|55 33333333|33

I don't know if is the rigth splitting you need, but changing the values in each [x..y] you can do what better fit your need. Remenber that character array are 0-based, then the first char is 0 and so on.

于 2012-10-16T11:55:20.707 回答
0

我不太遵守拆分规则。到底什么样的软件会写入文本文件?也许可以指示它改变结构?

话虽如此,插入管道很容易.Insert()

$a= '18240087A +17135555555 3333333333'
$a.Substring(0, $a.IndexOf('+')).Insert(2, '|').insert(5,'|').insert(8, '|').insert(11, '|').insert(13, '|')
# Output: 18|24|00|87|A|

# Rest of the line:
$a.Substring($a.IndexOf('+')+1)
# Output: 17135555555 3333333333

从那里您可以继续拆分其余的行数据。

于 2012-10-16T12:17:03.743 回答