Bash 列值扩展到多行

Bash 列值扩展到多行,bash,parsing,Bash,Parsing,我的档案如下: 1984 32768 5240.70 32768 5259.46 32768 5203.42 2016 32768 5244.38 32768 5223.40 32768 5263.07 2048 32768 5233.59 32768 5241.35 32768 5212.37 我想转换成这种格式: 1984 32768 5240.70 1984 32768 5259.46 1984 32768 5203.42 2016 32768 5244.38 2016 3

我的档案如下:

1984

32768 5240.70
32768 5259.46
32768 5203.42

2016

32768 5244.38
32768 5223.40
32768 5263.07

2048

32768 5233.59
32768 5241.35
32768 5212.37
我想转换成这种格式:

1984 32768 5240.70
1984 32768 5259.46 
1984 32768 5203.42
2016 32768 5244.38 
2016 32768 5223.40 
2016 32768 5263.07 
2048 32768 5233.59
2048 32768 5241.35
2048 32768 5212.37

使用bash可以轻松实现这一点吗?单线解决方案会更好。

这里是单线解决方案:)

读取时-arr;如果[${arr[@]}-eq 1];然后第一个=$arr;elif[${arr[@]}-gt 0];然后回显$first“${arr[@]}”;fi;完成output_file.dat
您可能更愿意将其作为一个函数使用,尽管您可以将其存储在
~/.bash\u别名中
~/.bashrc

convert_文件(){
input_file=“$1”
读取时-a arr;将行中的每个单词放入数组“arr”
如果[${arr[@]}-eq 1];则#行上只有一项
first=$arr#设置“first”值
elif[${arr[@]}-gt 0];然后#忽略空行(行上的项目超过零)
echo$first“${arr[@]}”#输出“first”值,然后是行
fi
完成<“$input_file”#将输入文件馈送到读取循环
}
这样称呼它:

转换文件输入文件.dat>输出文件.dat
对上述情况的解释:

  • $1
    这是命令行中的第一个参数
  • 读取时-arr
    循环输入并将每行上的每个字加载到数组“arr”中的一个元素中
  • [${arr[@]}-eq 1]
    测试数组“arr”(
    ${arr[@]}
    )的长度是否在数学上等于(
    -eq
    )1(即,我们在这行上只有一个单词)
  • 在bash中,数组有点奇怪。如果要查看整个数组,则需要
    [@]
    和大括号-
    ${arr[@]}
    。在数组变量名称前面加上
    #
    表示长度
  • first=$arr
    -
    $arr
    是从数组中获取第一个元素的惰性方法,但它可以工作:)
  • [${arr[@]}-gt 0]
    测试数组“arr”(
    ${arr[@]}
    )的长度在数学上是否大于(
    -gt
    )零(即我们没有空行)
  • echo$first“${arr[@]}”
    输出“first”值,后跟数组“arr”的内容
  • done<“$input\u file”
    -
    output_file.dat
    convert_file
    函数的输出重定向到文件
    output_file.dat
    。注意:文件将首先被截断!使用
    >
    而不是
    附加到给定文件

    • 与awk中的@Kind相同的逻辑:

      awk '1 == NF { key=$1 }; 2 == NF { print key " " $0 };' file
      
      我喜欢纯
      bash
      ,但是
      awk
      对于任何大小的文件都会更快、更高效

      作为练习,在
      sed
      中实现;o]

      sed -En '/^ *$/d; /^[0-9]{4}$/h; /^[0-9]{5} /{ x; G; s/\n/ /g; p; s/ .*//; h; }' file
      
      并解释说:

      sed -En '        # -E use extended pattern matching. -n only print when requested
        /^ *$/d;       # delete blank lines
        /^[0-9]{4}$/h; # store  header lines
      
        /^[0-9]{5} /{  # for data lines,
           x;          # swap the hold and pattern spaces
           G;          # add the hold (data) to the pattern (header)
           s/\n/ /;    # remove the newline between
           p;          # print the resulting line
           s/ .*//;    # remove the data
           h;          # put the header back into the hold space
        } ' file
      

      另一个例子,一个小小的状态机:

      awk'
      y | | NR==1{年=$1;getline;y=0;下一个}
      NF==0{y=1;next}
      {打印年份,$0}
      "档案"
      

      但是再看一遍,它会被连续的空行打断。

      @Kadir希望这个解释对你有用case语句更简洁一点:
      case${arr[@]}in 0:;;1) 年份=${arr[0]};;*)回音“$year${arr[*]}”;;esac
      良好点,已删除。