【问题标题】:awk define field patternawk 定义字段模式
【发布时间】:2013-06-17 11:45:04
【问题描述】:

我正在寻找一种使用 awk 将以下文本拆分为适当列的方法。

我有

[2013-06-17 13:30] [PACMAN] Running 'pacman -S cups'
[2013-06-17 13:30] [PACMAN] reinstalled cups (1.6.2-2)

所以,关于:

[2013-06-17 13:30] [PACMAN] Running 'pacman -S cups'

我想要:

$1 to be [2013-06-17 13:30]
$2 to be [PACMAN] 
$3 to be Running
$4 to be 'pacman -S cups'

为:

[2013-06-17 13:30] [PACMAN] reinstalled cups (1.6.2-2)

我想要:

$1 to be [2013-06-17 13:30]
$2 to be [PACMAN]
$3 to be reinstalled
$4 to be cups (1.6.2-2)

我已经做了很多谷歌搜索,找不到任何东西,我对 awk 很陌生

【问题讨论】:

  • 你的第二行呢? reinstalled cups (1.6.2-2)$3 还是别的什么?
  • 显示您对两行的预期输出并说出原因或我们只是在猜测。
  • 更新了两者的输出,我不希望一个命令同时满足这两种情况
  • 我想一个快速的脏修复方法是拆分空格,然后将我想要的变量合并到一个新变量中

标签: bash awk


【解决方案1】:

(以下内容似乎特定于 GNU awk;BSD awk 不支持将子组捕获到数组中。)

在这种情况下,您可能希望将整个字符串与特定的正则表达式进行匹配,而不是依赖awk 的字段拆分。

$ echo "[2013-06-17 13:30] [PACMAN] Running 'pacman -S cups'" | awk '
    {
       match($0, "^(\\\[.*\\\]) (\\\[.*\\\]) ([a-zA-Z]*) (.*)$", a);
       $1=a[1];
       $2=a[2];
       $3=a[3];
       $4=a[4];
       print $2
    }'
[PACMAN]

调用match 后,数组a 将填充来自$0 的与正则表达式匹配的文本。第 0 个元素是整个匹配字符串,其余元素设置为正则表达式中相应的括号组。

写正则表达式可能有更好的方法;我收到关于 \[ 被视为普通 [ 的警告,但总的来说它似乎有效。

【讨论】:

  • 更好的方法是将正则表达式括在/ / 中,而不是双引号。
【解决方案2】:

对于不优雅的方法,请参阅下面的第四条单行线。有用!!但你可能不想接受我的回答。该命令很嘈杂,您可能需要将 cmets 添加为“文档”以使其可维护。出于这个原因,我也将它作为.awk 文件包含在下面:-)

尽管如此,即使文件的格式相当简单,我认为最好的方法是使用@chepner 注释的正则表达式。如果只是因为它记录了自己。

~/$ cat test.txt 
[2013-06-17 13:30] [PACMAN] Running 'pacman -S cups'
[2013-06-17 13:30] [PACMAN] reinstalled cups (1.6.2-2)

1)第一栏:

 ~/$ awk -F '[\]]' '{print $1"]"}' test.txt 
 [2013-06-17 13:30]
 [2013-06-17 13:30]

2)第一列和第二列:

~/$ awk -F '[\]]' '{print $1"]" $2"]" }' test.txt 
[2013-06-17 13:30] [PACMAN]
[2013-06-17 13:30] [PACMAN]

3)全部三个:

~/$ awk -F '[\]]' '{print $1"]" $2"]"  $3}' test.txt
[2013-06-17 13:30] [PACMAN] Running 'pacman -S cups'
[2013-06-17 13:30] [PACMAN] reinstalled cups (1.6.2-2)

4) 同上,但将第三个字段拆分为数组a,以便分别打印Runningreinstalled。打印数组a (substr) 的子字符串,从第一个元素的length 的偏移量(os) 开始。

~/$ awk -F ']' '{split($3,a," "); os=(length(a[1])+2) ; print $1"]" $2"] " a[1]" " substr($3,os) }' test.txt
[2013-06-17 13:30] [PACMAN] Running 'pacman -S cups'
[2013-06-17 13:30] [PACMAN] reinstalled cups (1.6.2-2)

这是 BSD awk,所以它应该可以在 OSX 上运行。

# split.awk ... run with: awk -f split.awk  data.txt

BEGIN{
FS="]"   # Make the field separator be "]"
}
{
  # Split the third field into array "a"
  split($3,a," ") 
  os=(length(a[1])+2) 
   # Print the first two fields and a substring of array "a" (substr)            
   # starting at offset ("os") taken from the length of the first element 
   # right adjusted for two whitespaces.
  print $1"]" $2"] " a[1]" " substr($3,os) 
}

HTH。

【讨论】:

    【解决方案3】:

    如您的示例中所述,对于您想要的 3rd 和 5th 字段(以及缺少的 4th ),我有点困惑..

    第一种方式: 我的试验是基于引入一个新的分隔符来分隔字段...

    命令:

    ~/so_test> cat ztmp_bk | sed -n 's/]/]^/gp'| awk -F"^" '{print $1 "==" $2 "==" $3 }'
    

    输出:(由“==”标识的字段)

    [2013-06-17 13:30]== [PACMAN]== Running 'pacman -S cups'
    [2013-06-17 13:30]== [PACMAN]== reinstalled cups (1.6.2-2)
    

    第二种方式:

    另一种方法是将文件分成几部分,然后对第三个文件再次执行此操作,直到我们获得所需的单个列,然后我们可以使用粘贴与用户定义的分隔符将它们合并...

    像下面这样:(很粗糙,但你明白了!)

    Kaizen ~/so_test/test $ cat ztmp  | sed -n 's/]/]^/gp'| awk -F"^" '{print $1 "^" $2}' > ztmp1 ;
    Kaizen ~/so_test/test $  cat ztmp  | awk -F" " '{print   $4 "^" $5 $6 $7}' > ztmp2 ;
    Kaizen ~/so_test/test $  paste -d^ ztmp1 ztmp2 > ztmpF ;
    

    输出:这将为您提供一个以 ^ 分隔的新文件,因此您之前的 awk 命令现在可以处理此文件

    Kaizen ~/so_test/test $ cat ztmpF
    [2013-06-17 13:30]^ [PACMAN]^Running^'pacman-Scups'
    [2013-06-17 13:30]^ [PACMAN]^reinstalled^cups(1.6.2-2)
    
    Kaizen ~/so_test/test $ cat ztmpF | awk -F"^" '{print "first field:" $1 "\n" "second field:" $2 "\n" "third     field:" $3 "\n" "forth field:" $4 "\n" }'
    first field:[2013-06-17 13:30]
    second field: [PACMAN]
    third field:Running
    forth field:'pacman-Scups'
    
    first field:[2013-06-17 13:30]
    second field: [PACMAN]
    third field:reinstalled
    forth field:cups(1.6.2-2)
    

    这有帮助吗?

    【讨论】:

    • @JR93 任何时候你看到一个发布的解决方案,它使用 cat 和管道为命令提供输入,该命令可以很容易地打开文件本身(例如sed <script> ztmp_bk),这是一个巨大的危险信号发帖者对shell很陌生,还不明白。
    • @Ed Morton ,代表点公平地表明了社区的信任,除了我从不声称我是专家,也不是这个网站上的每个人都是专家。如果您不同意答案,则可以使用不赞成票选项。另外,如果您有更好的解决方案,请发布...学习新事物总是好的,我会对此表示赞成:)
    • 我认为向 OP(和您)提供一些关于如何在现在和将来确定预期解决方案的意见比在没有任何解释的情况下单击解决方案上的否决按钮更有用。我也不认为您的解决方案值得投反对票 - 直到 OP 告诉我们如何解析他的输入文件中的其他行,您的解决方案才有可能像其他任何人一样产生他想要的输出。
    • 感谢 cmets 到目前为止,但这对我没有帮助,因为该文件也是其他软件使用的日志文件,每次复制它似乎有点不必要,但我猜它一个选项
    猜你喜欢
    • 2020-03-29
    • 1970-01-01
    • 2016-12-06
    • 2017-12-13
    • 2013-08-04
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 2018-12-08
    相关资源
    最近更新 更多