【问题标题】:How to format an input file in bash to a special format?如何将 bash 中的输入文件格式化为特殊格式?
【发布时间】:2015-01-07 06:57:33
【问题描述】:

我有一个文本文件,我通过各种服务器 crontab 的 bash 脚本生成,格式如下:

0 sys1 server1
5 sys2 server2
2,3 sys3
0 sys3 server3
7 sys4 server4
....

我希望它变成这样:

0 sys1 server1
5 sys2 server2
2 sys3 server3
3 sys3 server3
0 sys3 server3
7 sys4 server4
....

我遇到的问题是,如果每个系统/服务器有两个或更多数字,它总是可以改变,并且每个服务器也可能有两个以上的 crontab 条目。

我的尝试是这样的:

    rday_old=""
    rsys_old=""
    rser_old=""
    [[ -e output ]] && rm output
    while read -u5 -r -a line; do
            rday=${line[0]}
            rsys=${line[1]}
            rser=${line[2]} 
            if [[ "$rsys_old" == "$rsys" ]]; then
                    echo "$rday_old $rsys_old $rser" >> output
            else
                    echo "$rday $rsys $rser" >> output    
            fi   
            rday_old=$rday
            rsys_old=$rsys
            rser_old=$rser  
    done 5< input_file

问题显然在于它不会像预期的那样工作。我不知道解决这个问题的最佳方法是什么。我的尝试没有考虑到如果一天的格式为 2,3 或 2,4,5 甚至 crontab 格式的最多 7 天(这将是一个 * 符号),则需要拆分这一天。此外,我可能需要存储多个 rday_old、rsys_old 和 rser_old。

我希望我以一种可以理解的方式陈述我的问题。 提前感谢您的帮助。

编辑:

在@anishsane 的回答之后,我将他的回答固定为

cat input | awk '{sys=$2; ser=$3; split($1,a,","); for(i in a){print a[i]" "  sys " " ser}}' > output

但它现在作为结果输出:

0 sys1 server1
5 sys2 server2
2 sys3 
3 sys3 server3
0 sys3 server3
7 sys4 server4
....

所以我快到了。

【问题讨论】:

    标签: bash


    【解决方案1】:

    gawk 方法:

    $ cat srvlist
    0 sys1 server1
    5 sys2 server2
    2,3 sys3
    0 sys3 server3
    7 sys4 server4
    
    $ awk '{sys=gensub("sys","","",$2); split($1,a,","); for(i in a){print a[i] " sys" sys " server" sys}}' srvlist
    0 sys1 server1
    5 sys2 server2
    2 sys3 server3
    3 sys3 server3
    0 sys3 server3
    7 sys4 server4
    

    解释:

    1. sys 变量从第二个字段中提取数字 - sys1、sys3 等。(这将分别包含 1、3)
    2. 以逗号分隔第一个字段为数组a
    3. a上循环根据需要打印字符串
    4. 输入文件中的字段 3 被忽略。至少对于提供的输入,字段 2 和 3 始终具有相同的数字。

    【讨论】:

    • 更新了原来的问题
    【解决方案2】:

    这是一个 Python 解决方案:

    #!/usr/bin/env python
    
    import fileinput
    import re
    
    for line in fileinput.input():
        matches = re.match('(\d),(\d) sys(\d+)', line)
        if matches:
            first, last, sys = matches.groups()
            for ii in range(int(first), int(last) + 1):
                print ii, 'sys' + sys, 'server' + sys
        else:
            print line,
    

    它使用一个简单的正则表达式来匹配第一个字段中带有逗号的行。如果匹配,则从数字范围的开头到结尾打印行。否则打印原始行。

    【讨论】:

    • 感谢您的回答。但如果可能的话,我更喜欢 bash 解决方案。否则,我需要使用的脚本数量会变得很复杂。上面的这个问题只是更大工作的一小部分
    【解决方案3】:

    现在解决了:

    [[ -e output ]] && rm output
    tac input > rev_input
    rser_old=""
    while read -u5 -r -a line; do
            rday=${line[0]}
            rsys=${line[1]}
            rser=${line[2]}
            OIFS=$IFS
            IFS=','
            for x in $rday
            do
                    [[ "$rser" == "" ]] && echo "$x $rsys $rser_old" >> output
                    [[ "$rser" != "" ]] && echo "$x $rsys $rser" >> output
            done
            rser_old=$rser
            IFS=$OIFS
    done 5< rev_input
    

    现在输出显然是反转的,但这根本不重要,因为这部分只是一个步骤,现在输出将被处理到另一个脚本。

    感谢提供的帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-10
      • 1970-01-01
      • 1970-01-01
      • 2019-05-15
      • 1970-01-01
      • 2014-05-20
      • 2021-01-11
      • 1970-01-01
      相关资源
      最近更新 更多