如何为其对应列的每个值重复一行

如何为其对应列的每个值重复一行

我想为其所有相应的值重复一行任何帮助

我的输入文件是这样的

    pos     COL1  COL2  COL3
    18691441    C   A   G
    18691572    G   C   G
    18691620    A   T   G
    18691716    C   G   C

我想要这样的输出

pos COL1    
18691441    COL1 C  
18691441    COL2 A  
18691441    COL3 G  
18691572    COL1 G  
18691572    COL2 C  
18691572    COL3 G  
18691620    COL1 A  
18691620    COL2 T  
18691620    COL3 G  
18691716    COL1 C  
18691716    COL2 G  
18691716    COL3 C

我试图重复一行,但它只是使它们重复,我正在使用

while read line; do for i in {1..3}; do echo "$line"; done; done < real2.txt

并给出输出:

pos       COL1 COL2 COL3
18691441    C   A   G
18691441    C   A   G
18691441    C   A   G
18691572    G   C   G
18691572    G   C   G
18691572    G   C   G
18691620    A   T   G
18691620    A   T   G
18691620    A   T   G
18691716    C   G   C
18691716    C   G   C
18691716    C   G   C

然后我从输入 1.txt 文件中提取 pos 并制作 1_pos.txt 并编写如下内容:

     pos
    18691441
    18691572
    18691620
    18691716
    for i in `cat 1_post.txt`;
    do
   x=$(grep -i "^$i" 1.txt | awk 'FNR == 1 {print $1"\t""COL1""\t"$2}' ) ;
   y=$(grep -i "^$i" 1.txt | awk 'FNR == 1 {print $1"\t""COL2""\t"$3}' ) ;
   z=$(grep -i "^$i" 1.txt | awk 'FNR == 1 {print $1"\t""COL3""\t"$4}' ) ;

    echo -e "$x""\n""$y""\n""$z";
    done  

这给了我带有列信息的输出,但是如果我有 405 列而不是 3 列,我不想为每列重复行 405 次,我尝试将其放入循环中,但它不起作用:

18691441    COL1    C
18691441    COL2    A
18691441    COL3    G
18691572    COL1    G
18691572    COL2    C
18691572    COL3    G
18691620    COL1    A
18691620    COL2    T
18691620    COL3    G
18691716    COL1    C
18691716    COL2    G
18691716    COL3    C

答案1

怎么样:

while read line col1 col2 col3; 
do 
    if [[ "$line" = "pos" ]]; then
        echo "pos COL"
        continue    
    fi
    echo "$line COL1 $col1"  
    echo "$line COL2 $col2"  
    echo "$line COL3 $col3"  
done < real2.txt

输出:

pos COL
18691441 COL1 C
18691441 COL2 A
18691441 COL3 G
18691572 COL1 G
18691572 COL2 C
18691572 COL3 G
18691620 COL1 A
18691620 COL2 T
18691620 COL3 G
18691716 COL1 C
18691716 COL2 G
18691716 COL3 C

答案2

awk方法:

awk 'BEGIN{OFS="\t";print "pos" OFS "COL1"}{if(NR==1){for(f=2;f<=NF;f++) c[f]=$f;}
     else{for(i=2;i<=NF;i++) print $1,c[i],$i}}' real2.txt

输出:

pos     COL1
18691441        COL1    C
18691441        COL2    A
18691441        COL3    G
18691572        COL1    G
18691572        COL2    C
18691572        COL3    G
18691620        COL1    A
18691620        COL2    T
18691620        COL3    G
18691716        COL1    C
18691716        COL2    G
18691716        COL3    C

OFS="\t"- 输出字段分隔符

print "pos" OFS "COL1"- 印刷标头线

if(NR==1){for(f=2;f<=NF;f++) c[f]=$f;- 从第一行/标题行收集列名称

for(i=2;i<=NF;i++) print $1, c[i], $iCOL...-根据相应的pos列值及其相应的列名称“按行”打印每个列 ( ) 值。

答案3

不要使用 shell 循环来处理文本。

awk是完成该任务的正确工具。但你只需要调用它一次:

awk -v OFS='\t' '
  NR == 1 {print $1, "name", "value"; split($0, header); next}
  {for (i = 2; i < NF; i++) print $1, header[i], $i}' < your-file

(一个变体罗曼的回答

答案4

while IFS= read -r l; do
   read -r -a A <<<"$l"
   case $l in
      'pos'[\ \   ]* )
         echo "${A[@]:0:2}"
         C=("${A[@]:1}")
         ;;

      * )
         p=0 x=${A[0]}
         for e in "${A[@]:1}"; do
            echo "$x ${C[$p]} $e"
            ((p++))
         done
         ;;
   esac
done < yourfile


sed -E '
   /\n/bloop

   y/\t/ /;s/  +/ /g;s/^ +//;s/ +$//

   1{
      h
         s/ /\n/2
      x
         s/ /\n/;s/.*\n//
      x
         s/\n.*//
      b
   }

   G;s/\n/ &/

   :loop
      #  1     2     3   4   5
      s/^(\S+ )(\S+) (.*)(\n)(\S+) ?/\1\5 \2\4\1\3\4/
      /\n$/{
         /\n.*\n/!d
      }
       P
      /\n.*\n/D
   tloop

' yourfile

结果

pos COL1
18691441 COL1 C
18691441 COL2 A
18691441 COL3 G
18691572 COL1 G
18691572 COL2 C
18691572 COL3 G
18691620 COL1 A
18691620 COL2 T
18691620 COL3 G
18691716 COL1 C
18691716 COL2 G
18691716 COL3 C

解释

  • 首先,我们将所有剩余的制表符转换为空格,然后压缩多个空格,最后修剪所有前导/尾随空格。
  • 我们对第一行进行特殊处理:
    • a) 复制该行。
    • b) 标记第二列的末尾以供稍后使用。
    • c) 将此标记行与存储在保留空间中的副本互换。
    • d) 剥离第一列,然后恢复显示 cols1,2 中的 &。
  • 对于所有其他行(2 到 eof),我们将列名称附加到该行。
  • 然后设置一个do-while循环,在每次迭代中我们以所示的方式重新排列字段,以便打印出列名称及其值。当我们看到一行的末尾并且它是该行中剩余的\n唯一字符时,我们停止。\n否则,我们只需砍掉前导部分并分支回到循环开头。

相关内容