【问题标题】:Print file in particular order in bash在bash中以特定顺序打印文件
【发布时间】:2019-02-21 14:22:27
【问题描述】:

我有包含内容的文件:

文件.txt:

Iteration 1
RAM: +456ms
Cache: +142ms (total +417ms)

Iteration 2
Spec: +152ms
Cache: +149ms (total +413ms)

Iteration 3
RAM: +184ms
Spec: +172ms
Searchms: +131ms (total +385ms)

First launch 4
RAM: +149ms
Searchms: +188ms

在每个First launch之间的这个文件中,内容可以不同,不是固定的(例如:First launch 3包含三个元素而First launch 2内容只有2个元素),所以任意数量的内容可以在First launch 一开始并不知道的模式。

预期输出:

RAM  456 184 149
Cache 142 149  
Spec 152 172
Searchms 131 188

由于不知道确切的方法,我已经尝试过这段代码。

我的代码:

for i in {1..4}
do
awk "/First launch $i/{flag=1;next} /First launch $((i+1))/{flag=0} flag" file.txt> fl$i.txt
sed -i 's/\+//g' fl$i.txt
sed -i 's/://g' fl$i.txt
sed -i 's/(.*//g' fl$i.txt
sed -i 's/ms//g' fl$i.txt
awk '{print $1 "\t" $2}' fl$i.txt
done

我的输出有两个问题: 我正在为每个错误的模式生成文件。另外我想在该时间之后删除ms,但它也会从模式名称中删除ms(例如:Searchms to Search)

输出:

fl1.txt: 
    RAM     456
    Cache   142
fl2.txt : 
    Spec    152
    Cache   149
fl3.txt  :
    RAM     184
    Spec    152
    Search  131
fl4.txt : 
    RAM     149
    Search  188

请建议我一种方法来获得预期的输出,而不会生成任何额外的文件,并限制在该时间后删除ms

【问题讨论】:

  • 顺便说一句,sed -i s/a/b/' file; sed -i 's/c/d/' file 更好地表示为 sed -i -e 's/a/b/' -e 's/c/d/' file,它只在整个文件中循环一次。
  • 你真的想要这个吗?您正在失去 RAM 和缓存(以及其他项目)之间的相关性,我认为这应该有用吗?

标签: bash shell awk sed


【解决方案1】:

一个使用awk的:

$ awk '
$1 !~ /^(|First)$/ {            # avoid forbidden keywords and empty lines
    gsub(/[^0-9]/,"",$2)        # remove non-numerals
    a[$1]=a[$1] OFS $2          # append to associative array 
}
END {                           # in the end
    for(i in a)                 # loop all keywords
        print i a[i]            # output
}' file

按 awk 默认顺序输出行(随机出现):

Cache: 142 149
Searchms: 131 188
Spec: 152 172
RAM: 456 184 149

【讨论】:

  • “First Launch”模式中的名称(例如:RAM、Cache等)一开始是未知的,它可以是模式中的任何名称。我的意思是它不是硬编码的,它是动态的。
  • 已更新以避免空记录和以First开头的记录。
【解决方案2】:
$ cat tst.awk
BEGIN { FS="[: ]+" }
/:/ { vals[$1] = vals[$1] OFS $2+0 }
END { for (key in vals) print key vals[key] }

$ awk -f tst.awk file
Cache 142 149
RAM 456 184 149
Searchms 131 188
Spec 152 172

【讨论】:

  • 请添加一些此代码正在执行的操作以及它如何帮助解决问题。
  • @Selaron 为什么?这完全是微不足道的,而且非常清楚 - 阅读 awk 文档后您不了解其中的哪些部分?
  • 因为机会很大,这会提高您帖子的质量:简洁是可以接受的,但更全面的解释会更好。
  • @Selaron 不,它不会。对此添加注释就像在代码i++ 中添加注释incrementing i。请不要在某些自动化工具看到纯代码答案时提出的“可能低质量”标志加上橡皮图章,因为它会为了解该领域的人做出决定而提高该标志 -如果您不知道该域,请不要发表评论,继续前进。
  • said Looks Ok 在低质量队列中。 “识别,然后改进或删除低质量的帖子”通常不需要领域知识。对于仅源代码的答案,我自然倾向于发表评论。剩下的就看作者了。不是有意冒犯你。
【解决方案3】:

这可能对你有用(GNU sed):

sed -E '/:/!d;s/.([0-9]+).*/\1/;H;x;s/((\n\S+) \S+)(.*)\2(.*)/\1\4\3/;h;$!d;x;s/.//' file

除包含: 之外的任何行都是噪音,因此请删除它们。

从每行中删除除键、空格和第一组整数之外的所有内容。

将结果附加到保持空间。

使用模式匹配,收集类似键的数据并保留在保持空间中。

删除除最后一行以外的所有内容。

在文件末尾,交换到保持空间,删除引入的换行符并打印结果。

【讨论】:

    【解决方案4】:

    Perl 单行:

    $ perl -nE 'if (/^(\w+):\s+\+(\d+)ms/) { push @{$keys{$1}}, $2 } END { while (($k, $vs) = each %keys) { say join(" ", $k, @$vs) }}' file.txt
    Spec 152 172
    Searchms 131 188
    Cache 142 149
    RAM 456 184 149
    

    (行的顺序会有所不同;如果重要,请通过管道对其进行排序)


    它是如何工作的:

    对于文件中的每一行,如果它与正则表达式 ^(\w+):\s+\+(\d)ms 匹配(行首有 1 个或多个字母数字字符,后跟冒号、空格、加号、1 个或多个数字,然后字母 m 和 s),它使用起始词作为键将数字添加到哈希中的适当数组中。然后它会打印出所有这些起始词及其关联的数组。

    与 awk 的答案基本相同,但它使用字符串而不是数组,因为 awk 没有像 perl 这样的真正数组,只有关联数组(在 perl 术语中称为哈希)。

    【讨论】:

    • 我不会 perl 语言,如果答案是 bash 会更好。
    • @Arya 你会在 shell 脚本中使用它。
    • 能否请您简要解释一下代码。我会更容易理解。还是谢谢!!
    • @Arya 添加了快速解释。
    【解决方案5】:

    另一个 Perl,使用段落模式 -00

    perl -00 -lnE ' 
                   while(/(^\S+):.+?(\d+)/gm ) {push(@{$kv{$1}},$2)} 
                END { foreach(keys %kv) { print "$_ @{$kv{$_}}" } }    '
    

    有输入

    $ cat arya.txt
    First launch 1
    RAM: +456ms
    Cache: +142ms (total +417ms)
    
    First launch 2
    Spec: +152ms
    Cache: +149ms (total +413ms)
    
    First launch 3
    RAM: +184ms
    Spec: +172ms
    Searchms: +131ms (total +385ms)
    
    First launch 4
    RAM: +149ms
    Searchms: +188ms
    
    $ perl -00 -lnE ' while(/(^\S+):.+?(\d+)/gm ) {push(@{$kv{$1}},$2)} END { foreach(keys %kv) { print "$_ @{$kv{$_}}" } } ' arya.txt
    RAM 456 184 149
    
    Cache 142 149
    
    Searchms 131 188
    
    Spec 152 172
    
    
    $
    

    【讨论】:

      【解决方案6】:

      简单地说:

      #!/bin/bash
      for i in RAM Cache Spec Searchms; do
          echo "$i `cat file.txt  | grep $i | grep -Eo '[0-9]{1,9}' | tr '\n' ' '`" >> out.txt
      done
      

      您可以在第 2 行更改顺序(for 循环)

      输出:

      $ cat out.txt 
      RAM 456 184 149 
      Cache 142 417 149 413 
      Spec 152 172 
      Searchms 131 385 188 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-09
        • 2021-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多