【问题标题】:How to print output in table format in shell script如何在shell脚本中以表格格式打印输出
【发布时间】:2022-01-01 14:38:35
【问题描述】:

我是 shell 脚本的新手。我想以表格格式分发文件的所有数据并将输出重定向到另一个文件。

我有以下输入文件File.txt

Fruit_label:1 Fruit_name:Apple
Color:Red
Type: S
No.of seeds:10
Color of seeds :brown
Fruit_label:2 fruit_name:Banana
Color:Yellow
Type:NS

我希望它看起来像这样

Fruit_label| Fruit_name |color| Type |no.of seeds |Color of seeds

1 |   apple |   red |  S |  10 |   brown 
2 |   banana|   yellow |  NS

我想从文本文件中逐行读取所有数据并制作像fruit_label,fruit_name,color,type,no.of种子,种子颜色一样的标题,然后按行打印所有分配的值。以上所有数据对于不同的水果来说是不同的。香蕉没有种子,所以希望将其行值保持为空白..

谁能帮帮我。

【问题讨论】:

  • 你试过什么? awk 是合适的工具,尽管您可以使用效率不高的其他工具的组合,但对于几千或更少的输入,这并不重要。对于更大的数据集(数十万条记录+)awk 将比其他解决方案快几个数量级。
  • 欢迎来到 SO。请收下tour 并阅读How to Ask

标签: linux shell


【解决方案1】:

另一种方法是“装饰和处理”方法。什么是“装饰和工艺”装饰是获取您拥有的文本并用另一个分隔符装饰它,以使字段拆分更容易 - 就像在您的情况下,您的字段可以包含包含的空格以及字段之间的 ':' 分隔符-名称和值。 ':' 周围的空格不一致 - 这使得处理......简单地成为一场噩梦。

因此,与其担心分隔符是什么,不如想想“字段应该是什么?”然后在字段之间添加一个新的分隔符 (Decorate),然后使用 awkProcess

这里sed 用于装饰您的输入,使用'|' 作为分隔符(第二次调用消除了最后一个字段之后的'|'),然后使用更简单的awk 过程到split()':' 上的字段以获取字段名称和字段值,其中字段值被简单地打印并且字段名称存储在数组中。当发现重复的字段名时 -- 它用作seen 变量来指定记录之间的更改,例如

sed -E 's/([^:]+:[[:blank:]]*[^[:blank:]]+)[[:blank:]]*/\1|/g' file | 
sed 's/|$//' |
awk '
  BEGIN { FS = "|" }
  {
    for (i=1; i<=NF; i++) {
      if (split ($i, parts, /[[:blank:]]*:[[:blank:]]*/)) {
        if (! n || parts[1] in fldnames) {
          printf "%s %s", n ? "\n" : "", parts[2]
          delete fldnames
          n = 1
        }
        else
          printf " | %s", parts[2]
        fldnames[parts[1]]++
      }
    }
  }
  END { print "" }
'

示例输出

您在file 中输入您将拥有:

 1 | Apple | Red | S | 10 | brown
 2 | Banana | Yellow | NS

您还将看到一个 “Decorate-Sort-Undecorate” 用于通过 “装饰” 使用新的最后一个字段,对该字段进行排序,然后 "Undecorating" 以在排序完成时删除附加字段。这允许按可能是任意两列之和(或组合)等的数据进行排序......

【讨论】:

  • 新年快乐..
【解决方案2】:

这是我的解决方案。这是一份新年礼物,通常你必须展示你迄今为止所做的尝试,我们会帮助你,而不是为你做。

免责声明一些大师可能会想出一个更简单的 awk 版本,但这是可行的。

文件 script.awk

# Remove space prefix
function ltrim(s) { sub(/^[ \t\r\n]+/, "", s); return s }
# Remove space suffix
function rtrim(s) { sub(/[ \t\r\n]+$/, "", s); return s }
# Remove both suffix and prefix spaces
function trim(s) { return rtrim(ltrim(s)); }

# Initialise or reset a fruit array
function array_init() {
    for (i = 0; i <= 6; ++i) {
        fruit[i] = ""
    }
}

# Print the content of the fruit
function array_print() {
    # To keep track if something was printed.  Yes, print a carriage return.
    # To avoid printing a carriage return on an empty array.
    printedsomething = 0
    for (i = 0; i <= 6; =+i) {
        # Do no print if the content is empty
        if (fruit[i] != "") {
            printedsomething = 1
            if (i == 1) {
                # The first field must be further split, to remove "Fruit_name"
                # Split on the space
                split(fruit[i], temparr, / /)
                printf "%s", trim(temparr[1])
            }
            else {
                printf " |   %s", trim(fruit[i])
            }
        }
    }
    if ( printedsomething == 1 ) {
        print ""
    }
}

BEGIN {
    FS = ":"
    print "Fruit_label| Fruit_name |color| Type |no.of seeds |Color of seeds"
    array_init()
}

/Fruit_label/ {
    array_print()
    array_init()
    fruit[1] = $2
    fruit[2] = $3
}
/Color:/ {
    fruit[3] = $2
}
/Type/ {
    fruit[4] = $2
}
/No.of seeds/ {
    fruit[5] = $2
}
/Color of seeds/ {
    fruit[6] = $2
}

END { array_print() }

  • 要执行,请致电awk -f script.awk File.txt
  • awk 每行处理一个文件行。所以想法是将水果信息存储到一个数组中。
  • 每次找到“Fruit_label:.....”行时,打印当前的水果并开始一个新的。
  • 由于每行都是按顺序读取的,因此您可以根据模式告诉awk 如何处理每行。
  • 模式是包含在每个代码段开头的// 字符之间的内容。
  • 难点:由于第一行包含每个水果的 2 条信息,我在 : char 上剪断了行,因此 Fruit_label 将包含“Fruit_name”。
  • 即:第一行被剪成这样:$1 = Fruit_label, $2 = 1 Fruit_name, $3 = Apple
  • 这就是array_print() 函数如此复杂的原因。
  • 修剪功能可以删除空格。
  • 与 Apple 一样,Type: S: 上拆分时将产生 S

如果符合你的要求,请看https://stackoverflow.com/help/someone-answers接受。

【讨论】:

    猜你喜欢
    • 2015-05-18
    • 2014-04-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多