用于格式化文本,合并行,添加制表符的shell脚本

时间:2014-09-18 19:35:46

标签: bash shell

20140918-17:31:19.835
34=11
52=20140918-17:31:19.812
273=17:31:19.797
273=17:31:19.797
273=17:31:19.797
273=17:31:19.797
20140918-17:31:19.837
34=12
52=20140918-17:31:19.813
273=17:31:19.797
273=17:31:19.797
273=17:31:19.797
273=17:31:19.797
20140918-17:31:19.838
34=13
52=20140918-17:31:19.813
273=17:31:19.797
273=17:31:19.797
273=17:31:19.797
273=17:31:19.797

我有这个输入,想要像这样格式化:

34=11 20140918-17:31:19.835
    52=20140918-17:31:19.812
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
34=12 20140918-17:31:19.837
    52=20140918-17:31:19.813
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
34=13 20140918-17:31:19.838
    52=20140918-17:31:19.813
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797

我没有shell脚本编写经验,我担心这个问题可能不合适,但是如果你能指出一个很好的shell脚本教程可以让我开始,我会很感激!

4 个答案:

答案 0 :(得分:4)

您可以使用awk

执行此操作
awk '!/=/{m=$0; next}m{$0=$0 FS m; m=0}/^52=/{$0="\t"$0}/^273=/{$0="\t\t"$0}1' file

工作原理:

  • !/=/{m=$0; next} - 如果该行不包含=,则行记录($0)将分配给m变量。 next跳到下一行,因为无需进一步处理。

  • m{$0=$0 FS m; m=0} - 如果定义了m(大于零),请将当前行($0)附加到字段分隔符(FS)和变量m(上一行)。最后,将m变量重置为零,因为我们需要确保此代码块在不包含=字符的行之后立即执行。

  • /^52=/{$0="\t"$0} - 如果当前行以52=开头,则在当前行记录($0)前加上制表符(\t

  • /^273=/{$0="\t\t"$0} - 如果当前行以273=开头,请在当前行记录前加上两个制表符。

  • 1 - 无论条件如何,这只是一句简短的说法{print}1只是告诉awk print是真的。如果条件为真且没有提供下面的代码块,则awk的默认操作就是打印,你可以用任何真实的东西替换它。

在任何UNIX系统上,awk都是用于处理文本文件的语言。

我发现this intro非常简洁。此外,awk.info有大量的概述和教程。就文档而言,GNU Awk User's Guide非常全面。

答案 1 :(得分:2)

以下是使用sed

的示例
sed -r '
    /^2014/ {                          # For lines starting with 2014
        N;                             # Append next line to pattern space
        s/^([^\n]+)\n([^\n]+)/\2 \1/;  # Merge the first line with second
    }
    /^52/ {                            # For lines starting with 52
        s/^/\t/                        # Add a tab in the front of the line
    }
    /^273/ {                           # For lines starting with 273
        s/^/\t\t/                      # Add a tab in the front of the line
    }' file
34=11 20140918-17:31:19.835
    52=20140918-17:31:19.812
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
34=12 20140918-17:31:19.837
    52=20140918-17:31:19.813
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
34=13 20140918-17:31:19.838
    52=20140918-17:31:19.813
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797
        273=17:31:19.797

作为一个单行:

sed -r '/^2014/N;s/^([^\n]+)\n([^\n]+)/\2 \1/;/^52/s/^/\t/;/^273/s/^/\t\t/' file

答案 2 :(得分:0)

AWK与Jaypal一样出色,约翰用解决方案描述。在您是新手时,您可以通过运行基本的Unix / Linux级别命令来执行相同的操作,并且通过查看其手册页,它将帮助您了解这些命令正在执行的操作。

请注意,以下解决方案不是像John / JayPal所提供的那样有效的解决方案,但会让您完全了解我的意思以及您的输出请求。

假设您的文件名是1.txt“,其中包含数据,请运行以下 runme.sh

 #!/bin/bash
 grep "^[0-9][0-9]=[0-9][0-9]$" 1.txt > 2-2.txt
 grep "^[0-9][0-9][0-9][0-9]*.*-[0-9][0-9]*\:[0-9][0-9]*.*\.[0-9][0-9]*$" 1.txt > datetime.txt
 grep "^[0-9][0-9]=.*-[0-9][0-9]*\:[0-9][0-9]*.*\.[0-9][0-9]*$" 1.txt > equal_datetime.txt
 grep "^[0-9][0-9][0-9]=.*[0-9]$" 1.txt > 3_eq_lines.txt

 paste 2-2.txt datetime.txt equal_datetime.txt  > headers.txt
 c=1; while read line1 line2 line3; do echo -e "$line1 $line2\n    $line3"; echo -e "`tail -n +$c 3_eq_lines.txt | head -4|sed "s/^/        /"`"; ((c+=3)); done < headers.txt
 rm 2-2.txt datetime.txt equal_datetime.txt 3_eq_lines.txt headers.txt

答案 3 :(得分:0)

也许是perl

perl -lnE '$l1=$_,next unless m/=/;        #store the line without =
           s/$/ $l1/ if m/^\d\d=\d\d$/;    #merge this line with the stored
           s/^/\t/ if m/^\d+=\d{8}/;       #if the = is followed by 8 digits -> 1xtab
           s/^/\t\t/ if m/^\d+=\d\d:/;     #if the = is followed by 2digits and : -> 2xtab
           print $_;' filename