Bash

bash 將行轉換為列

  • October 25, 2022

我有數千個看起來像這樣的文件:

org_files:

reference_group1 _CEFNB_
group1          ACBF_BG
group2          ACB_MBM
...

對於每個文件,我需要將行轉換為列,然後添加一個包含 reference_group 索引的列(稱為 id_from_reference_group),如下所示:

轉換後的文件


# explanation of each column
# reference_group_id    serials_from_ref_group  group_id    serials_from_group
reference_group1            _                group1            A
reference_group1                             group1            C
reference_group1            E                group1            B
reference_group1            F                group1            F
reference_group1            N                group1            _
reference_group1            B                group1            B
reference_group1            _                group1            G
reference_group1            _                group2            A
reference_group1            C                group2            C
reference_group1            E                group2            B
reference_group1            F                group2            _
reference_group1            N                group2            M
reference_group1            B                group2            B
reference_group1            _                group2            M

每組的 org_files 中第 2 列的內容由重複的字母組成。並且第二列始終具有相同的長度。

我試過了

input="reference_group1 _CEFNB_
group1          ACBF_BG
group2          ACB_MBM"

while IFS=" " read -ra line; do # read input line by line
# loop over fields
 for (( i = 0 ; i < ${#line[@]}; i++ )); do
   # only split 2nd field
   if [[ $i == 1 ]]
   then
     for j in ${line[$i]}
     do
       # loopover each letter of 2nd field
       for (( j=0; j<${#line[$i]}; j++ ))
       do
         echo "${line[$i-1]}  ${line[$i]:$j:1}"
       done
     done
   fi

 done
done <<< "$input"

但我只得到這樣的結果

reference_group1  _
...
group1  A
...
group2  M

而且程式碼有點亂。如果有簡單的命令會更好。謝謝!

您可以使用類似 ( tst.awk) 的腳本來使用 awk:

BEGIN{print "#reference_group_id serials_from_ref_group group_id serials_from_group"}
$1 ~ /^reference_/ {ref=$1;ser=$2;next}
{
       for(i=1;i<=length($2);i++){
               print ref, substr(ser,i,1), $1, substr($2,i,1)
       }
}

我想你reference_group_id總是開始reference_將它儲存到一個名為 var 的 varref中,然後儲存serials_from_ref_groupser. 然後我們在一個循環中使用這兩個 var。

然後這樣的一行應該可以工作:

awk -f tst.awk file

由於您的輸出是由您格式化的,column您可以將輸出通過管道傳輸到column -t

awk -f tst.awk file | column -t

awk 腳本說明:

  • BEGIN只執行一次,在第一個輸入記錄之前
  • $1 ~ /^reference_/if$1匹配正則表達式^reference_
  • length($2)第二個欄位的長度
  • substr(ser,i,1)子串的ser起始i位置和長度1

引用自:https://unix.stackexchange.com/questions/722369