Board logo

标题: [转载代码] 使用PowerShell来完成像awk一样对多个文件的筛选(一) [打印本页]

作者: DAIC    时间: 2013-10-17 09:29     标题: 使用PowerShell来完成像awk一样对多个文件的筛选(一)

本篇文章引用的小例子来自如下链接:
http://bbs.chinaunix.net/thread-577044-1-1.html

又是一篇重量级的精华帖, 主要讲解了awk在shell中的重要作用. 编写本篇例子, 费了我很长时间, 一开始我就使用awk的思路, 试图利用PowerShell完成. 写完后, 依然还是模仿awk的风格, 并且整个代码更加冗长, 我沉思半晌, 终于领悟到了一个关键性的问题. 正如, PowerShell团队leader所说: "Unix世界文件, 大都是字符串, 因此在Unix环境下, 针对文本的处理工具譬如: 'awk, sed, join, paste, uniq, sort 和column'等等都异常强大." 在Windows的环境中, 所有信息被抽象, 因此, PowerShell 的特性也就必须进行一定的扩展, 才能更好的适应文本操作. 下面对于每种问题, 我都会给出相应的代码, 这里用到了很多很多PowerShell中的知识, 如果想真正看懂, 需要把基本功大扎实. 基本功越好, 你就一定遇到更少的障碍.

1. 用某一文件的一个域替换另一个文件中的的特定域

PS C:\PowerShell\test1> gc passwd s2002408030068:x:527:527::/home/dz02/s2002408030068:/bin/pw s2002408032819:x:528:528::/home/dz02/s2002408032819:/bin/pw s2002408032823:x:529:529::/home/dz02/s2002408032823:/bin/pw

PS C:\PowerShell\test1> gc shadow
s2002408030068:$1$d8NwFclG$v4ZTacfR2nsbC8BnVd3dn1:12676:0:99999:7::: s2002408032819:$1$UAvNbHza$481Arvk1FmixCP6ZBDWHh0:12676:0:99999:7::: s2002408032823:$1$U2eJ3oO1$bG.eKO8Zupe0TnyFhWX9Y.:12676:0:99999:7:::


我们希望用shadow中第二个域中的字符串替换passwd中的第二个域的'x'. 代码示例如下:

PS C:\PowerShell\test1> gc shadow | %{ $hash = @{} } { $key,$value = $_.trim().split(':')[0,1]; $hash.$key = $value }


我们初始化了一个名称为hash的HashTable, 接下来用了一个perl的多值赋值语句将我们需要信息用数组slice技巧赋值, 最后添加到hash中. 貌似分割太复杂了, sigh...接下来,我们还要将这些数据与passwd中的信息进行合并.

PS C:\PowerShell\test1> switch -f passwd { { $_ -notmatch '^\s*$' } { $ofs = ":"; $input = $_.split(':'); $input[1] = $hash[$input[0]]; "$input" } } s2002408030068:$1$d8NwFclG$v4ZTacfR2nsbC8BnVd3dn1:527:527::/home/dz02/s2002408030068:/bin/pw s2002408032819:$1$UAvNbHza$481Arvk1FmixCP6ZBDWHh0:528:528::/home/dz02/s2002408032819:/bin/pw s2002408032823:$1$U2eJ3oO1$bG.eKO8Zupe0TnyFhWX9Y.:529:529::/home/dz02/s2002408032823:/bin/pw


完成任务, 不过我确实用了很多代码, 看起来很复杂. 这里我特意使用了强大的switch来操作文件, 分支条件也使用了表达式.

写到这里, 我觉得很郁闷, 如果我们能获得awk默认的特性, 设置一些默认的变量, 那么我就会更加简单了.

***********************************
我最终决定, 扩展自己的哦PowerShell, 完成一些令人crazy的事情. 让PowerShell具有awk的能力. 以下代码绝对原创:
***********************************
  1. filter awk ([scriptblock] $cmd = $args[0], [regex] $delimiter='\s+')
  2. {
  3.     $line = @();
  4.     $nf = 0;
  5.     $line = @($delimiter.split($_.Trim()));
  6.     $nf = $line.length;
  7.     $0 = $_;
  8.     for ($i = 1; $i -le $nf; $i++)
  9.     {
  10.         Invoke-Expression "`$i = '$($line[$i - 1])'"
  11.     }
  12.     & $cmd
  13. }
复制代码
好了, 虽然他还不能算得上好使, 但是一般工作都可以完成了. 下面我们测试一下他. 目前他只能支持从管道读取数据.

2. 连接两个文件, 连接属性是某个域上的字串

我们先看下输入数据:

PS C:\PowerShell\test2> gc file1
0011AAA 200.00 20050321
0012BBB 300.00 20050621
0013DDD 400.00 20050622
0014FFF 500.00 20050401

PS C:\PowerShell\test2> gc file2
I0011 11111
I0012 22222
I0014 55555
I0013 66666


我们需要根据file1中第一个域上前4个字符和file2上第一个域的2到5个字符进行比较. 将file2第二个域的数据连接到file1上. 我们来测试下awk的功能吧:

PS C:\PowerShell\test2> $hash = @{}
PS C:\PowerShell\test2> gc file2 | awk -cmd {$hash[$1.substring(1,4)] = $2}
PS C:\PowerShell\test2> gc file1 | awk -cmd { "$0 $($hash[$1.substring(0,4)])" }
0011AAA 200.00 20050321 11111
0012BBB 300.00 20050621 22222
0013DDD 400.00 20050622 66666
0014FFF 500.00 20050401 55555


OK了, 是不是简单了很多呢??

在下一次中, 我将会继续完成3,4题. 希望, 今天的例子足以让你感受到PowerShell的强大. awk 大约花费了我30分钟的时间. 这种扩展带来了更加快速的处理效率.

http://blog.chinaunix.net/uid-9781829-id-1997703.html




欢迎光临 批处理之家 (http://bbs.bathome.net/) Powered by Discuz! 7.2