读取文本文件,改变某些行的列顺序

时间:2017-11-10 03:47:19

标签: bash shell awk sed

我的输入文件格式为:

   0     1     0     0     0     1     1     0     0    0 / 1    0 / 1    0 / 1
   0     1     0 3/4     1     0     0 1/4     0     0    -1 1/2
   0    -1     0 1/4    -1     0     0 3/4     0     0     1 1/2

我想重新排列其中包含分数的行的顺序。目前我有:

#!bin/bash
filename="input.txt"
while ((i++)); read -r line; do
  re='[0-9][/][0-9]';
  if [[ $line =~ $re ]]
    then
      echo $line
  fi
done < "$filename"

将回显第二和第三行。是否有一个awk或sed命令我可以使用这两行来改变它们的顺序(将第一行保留为原样)

$1,$2,$3,$5,$6,$7,$9,$10,$11,$4,$8,$12

这将使我的文件现在看起来像

   0     1     0     0     0     1     1     0     0    0 / 1    0 / 1    0 / 1
   0     1     0     1     0     0     0     0    -1 3/4 1/4 1/2
   0    -1     0    -1     0     0     0     0     1 1/4 3/4 1/2

3 个答案:

答案 0 :(得分:3)

最好使用awk完成:

awk -v OFS='\t' '/[0-9]\/[0-9]/{print $1,$2,$3,$5,$6,$7,$9,$10,$11,$4,$8,$12; next} 1' file

0     1     0     0     0     1     1     0     0    0 / 1    0 / 1    0 / 1
0   1   0   1   0   0   0   0   -1  3/4 1/4 1/2
0   -1  0   -1  0   0   0   0   1   1/4 3/4 1/2

答案 1 :(得分:0)

@anubhava是比我更好的解决方案。自从我写了其他代码之后,请注意。

#!/bin/bash

filename="input.txt"

awk '
{
for (i=1; i <= NF; i++)
  if ( $(i+1) == "/" || $i == "/" || $(i-1) == "/") {
    printf "MM%sMM",$i" "$(i+1)" "$(i+2)
    i = i+2
  } else if ( match ($i, /^[[:digit:]]\/[[:digit:]]/) ) {
    printf "MM%sMM",$i
  } else {
    printf "MM%sMM",$i
  }
  printf "\n"
}' $filename | sed -e 's/MMMM/MM/g;s/^MM//;s/MM/\t/g' 

答案 2 :(得分:0)

你可以用awk轻松做到这一点,但我认为定义游戏规则很重要。 根据以下假设:

  • 分数是以下形式的任何内容:a/ba / ba/ b
  • 如果分数出现在第4列或第8列中,请对列进行重新洗牌。
  • 您希望保持格式正确

考虑到这一点,您可以使用以下awk代码

awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
     { gsub(/[[:blank:]]*\/[[:blank:]]*/,"/",$0); $0=$0 }
     ($4 ~ /\//) || ($8 ~ /\//) { 
        $12=$4" "$8" "$12
        $4=""; $8=""
        $0=$0
     }                                           
     { printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12 }
    ' file.txt

执行以下操作:

  • 将所有" / "或其中的任何变体替换为/

  • $0 = $0重新定义字段,即前两行中的字段 将从18个字段移至12

  • 如果分数(即/)出现在字段4或8中,则重新定义字段12,删除字段4和8并再次执行$0=$0

  • 以正确的格式打印。

注意:在上面的例子中,分数具有不同的输出(无空格)

以上将给出以下输出:

   0     1     0     0     0     1     1     0     0    0/1    0/1    0/1
   0     1     0     1     0     0     0     0    -1    3/4    1/4    1/2
   0    -1     0    -1     0     0     0     0     1    1/4    3/4    1/2

如果您不想在第一行更改分数,那么您可以像这样轻松地完成

awk 'BEGIN{format="%4s%6s%6s%6s%6s%6s%6s%6s%6s%7s%7s%7s\n"}
     (NF>12) { print; next }
     { 
        $12=$4" "$8" "$12
        $4=""; $8=""
        $0=$0
        printf format,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12
     }
    ' file.txt

这里假设,

  • 如果一行有超过12个字段,只需打印

  • 否则,将列洗牌

然而,这不太稳健,因为一切都取决于分数在第4,第8和第12列中的输入方式。即他们必须键入没有空格。输出如下:

   0     1     0     0     0     1     1     0     0    0 / 1    0 / 1    0 / 1
   0     1     0     1     0     0     0     0    -1    3/4    1/4    1/2
   0    -1     0    -1     0     0     0     0     1    1/4    3/4    1/2