简体   繁体   English

如何在 shell 脚本中以表格格式打印 output

[英]How to print output in table format in shell script

I am new to shell scripting.. I want to disribute all the data of a file in a table format and redirect the output into another file.我是 shell 脚本的新手。我想以表格格式分发文件的所有数据并将 output 重定向到另一个文件。

I have below input file File.txt我有以下输入文件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

I want it to looks like this我希望它看起来像这样

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

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

I want to read all the data line by line from text file and make the headerlike fruit_label,fruit_name,color,type, no.of seeds, color of seeds and then print all the assigned value in rows.All the above data is different for different fruits for ex.我想从文本文件中逐行读取所有数据并制作像fruit_label,fruit_name,color,type,no.of种子,种子颜色一样的标题,然后按行打印所有分配的值。上述所有数据都不同例如不同的水果。 banana dont have seeds so want to keep its row value as blank..香蕉没有种子,因此希望将其行值保持为空白..

Can anyone help me here.有人能帮我一下吗。

Here is my solution.这是我的解决方案。 It is a new year gift, usually you have to demonstrate what you have tried so far and we help you, not do it for you.这是一份新年礼物,通常您必须展示您迄今为止所做的尝试,我们会帮助您,而不是为您做。

Disclaimer some guru will probably come up with a simpler awk version, but this works.免责声明一些大师可能会想出一个更简单的 awk 版本,但这有效。

File script.awk文件脚本.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() }

  • To execute, call awk -f script.awk File.txt要执行,调用awk -f script.awk File.txt
  • awk processes a file line per line. awk每行处理一个文件行。 So the idea is to store fruit information into an array.所以想法是将水果信息存储到一个数组中。
  • Every time the line "Fruit_label:....." is found, print the current fruit and start a new one.每次找到“Fruit_label:.....”行时,打印当前的水果并开始一个新的。
  • Since each line is read in sequence, you tell awk what to do with each line, based on a pattern.由于每一行都是按顺序读取的,因此您可以根据模式告诉awk如何处理每一行。
  • The patterns are what are enclosed between // characters at the beginning of each section of code.模式是包含在每段代码开头的//字符之间的内容。
  • Difficulty: since the first line contains 2 information on every fruit, and I cut the lines on : char, the Fruit_label will include "Fruit_name".难度:由于第一行包含每个水果的 2 个信息,我在: char 上剪断了行,Fruit_label 将包含“Fruit_name”。
  • Ie: the first line is cut like this: $1 = Fruit_label , $2 = 1 Fruit_name , $3 = Apple即:第一行剪成这样: $1 = Fruit_label , $2 = 1 Fruit_name , $3 = Apple
  • This is why the array_print() function is so complicated.这就是为什么array_print() function 如此复杂的原因。
  • Trim functions are there to remove spaces.修剪功能可以删除空格。
  • Like for the Apple, Type: S when split on the : will result in S与 Apple 一样,在 : 上拆分时Type: S :导致S

If it meets your requirements, please see https://stackoverflow.com/help/someone-answers to accept it.如果符合您的要求,请参阅https://stackoverflow.com/help/someone-answers接受它。

Another approach, is a Decorate & Process approach.另一种方法是装饰和工艺方法。 What is Decorate & Process ?什么是装饰和工艺 To Decorate is to take the text you have and decorate it with another separator so make field-splitting easier -- like in your case your fields can contain included whitespace along with the ':' separator between the field-names and values.装饰是获取您拥有的文本并用另一个分隔符装饰它,以便更轻松地进行字段拆分 - 就像在您的情况下,您的字段可以包含包含的空格以及字段名称和值之间的':'分隔符。 With your inconsistent whitespace around ':' -- that makes it a nightmare to process... simply. ':'周围的空格不一致 - 这使得处理......简单地说是一场噩梦。

So instead of worrying about what the separator is, think about "What should the fields be?"因此,与其担心分隔符是什么,不如想想“字段应该是什么?” and then add a new separator ( Decorate ) between the fields and then Process with awk .然后在字段之间添加一个新的分隔符(装饰),然后使用awk处理

Here sed is used to Decorate your input with '|'这里sed用于用'|'装饰您的输入as separators (a second call eliminates the '|' after the last field and then a simpler awk process is used to split() the fields on ':' to obtain the field-name and field-value where the field-value is simply printed and the field-names are stored in an array. When a duplicate field-name is found -- it is uses as seen variable to designate the change between records, eg作为分隔符(第二次调用消除了最后一个字段之后的'|' ,然后使用更简单的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 "" }
'

Example Output示例 Output

With your input in file you would have:通过您在file中的输入,您将拥有:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM