我的輸入制表符分隔檔案是這樣的:
13435 830169 830264 a 95 y 16
09433 835620 835672 x 46
30945 838405 838620 a 21 c 19
94853 850475 850660 y 15
04958 865700 865978 c 16 a 98
在前三列之后,檔案在下一列中顯示變數及其值。我需要更改資料結構,以便在前三列之后,有這樣的變數列:
a x y c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
是否有任何代碼可以在 linux 上執行此操作?檔案大小為 7.6 MB,總行數約為 450,000。變數總數為四個。
謝謝
uj5u.com熱心網友回復:
在純 bash 中(需要 bash 4.0 或更新版本):
#!/bin/bash
declare -A var
printf '\t\t\ta\tx\ty\tc\n'
while IFS=$'\t' read -ra fld; do
var[a]="" var[x]="" var[y]="" var[c]=""
for ((i = 3; i < ${#fld[@]}; i = 2)); do
var["${fld[i]}"]=${fld[i 1]}
done
printf '%s\t' "${fld[@]:0:3}"
printf '%s\t%s\t%s\t%s\n' "${var[a]}" "${var[x]}" "${var[y]}" "${var[c]}"
done < file
uj5u.com熱心網友回復:
如果你知道你有4個變數a,x,y,c,并作為制表符分隔的檔案,該檔案的格式,你想要的確切格式如圖所示的輸出,你可以簡單地用“蠻力”的方法,你檢查欄位的內容4,并6為變數名稱并輸出欄位的值5或7使用printf.
例如,知道變數名稱后,您可以簡單地輸出標題行,然后按如下方式處理每條記錄:
awk -F"\t" '
FNR==1 {
print "\t\t\t a x y c"
}
{
printf "%-8s%8s%8s ", $1, $2, $3
if ($4=="a")
printf "%-5s", $5
else if ($6=="a")
printf "%-5s", $7
else
printf "%-5s", " "
if ($4=="x")
printf "%-5s", $5
else if ($6=="x")
printf "%-5s", $7
else
printf "%-5s", " "
if ($4=="y")
printf "%-5s", $5
else if ($6=="y")
printf "%-5s", $7
else
printf "%-5s", " "
if ($4=="c")
printf "%-5s\n", $5
else if ($6=="c")
printf "%-5s\n", $7
else
print ""
}
' tabfile
示例使用/輸出
有了您的輸入,tabfile您將擁有:
$ awk -F"\t" '
> FNR==1 {
> print "\t\t\t a x y c"
> }
> {
> printf "%-8s%8s%8s ", $1, $2, $3
>
> if ($4=="a")
> printf "%-5s", $5
> else if ($6=="a")
> printf "%-5s", $7
> else
> printf "%-5s", " "
>
> if ($4=="x")
> printf "%-5s", $5
> else if ($6=="x")
> printf "%-5s", $7
> else
> printf "%-5s", " "
>
> if ($4=="y")
> printf "%-5s", $5
> else if ($6=="y")
> printf "%-5s", $7
> else
> printf "%-5s", " "
>
> if ($4=="c")
> printf "%-5s\n", $5
> else if ($6=="c")
> printf "%-5s\n", $7
> else
> print ""
> }
> ' tabfile
a x y c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
這提供了所需的輸出。對于 450,000 行輸入,這種一次性方法也將非常有效。由于這對于命令列腳本來說有點長,您可以簡單地將它放在 awk 腳本中并使用檔案名呼叫它。如果您有任何疑問,請告訴我。
作為腳本檔案
用作腳本檔案,只需將內容放入檔案中并使其可執行,例如
#!/usr/bin/awk -f
BEGIN { FS="\t" }
FNR==1 {
print "\t\t\t a x y c"
}
{
printf "%-8s%8s%8s ", $1, $2, $3
if ($4=="a")
printf "%-5s", $5
else if ($6=="a")
printf "%-5s", $7
else
printf "%-5s", " "
if ($4=="x")
printf "%-5s", $5
else if ($6=="x")
printf "%-5s", $7
else
printf "%-5s", " "
if ($4=="y")
printf "%-5s", $5
else if ($6=="y")
printf "%-5s", $7
else
printf "%-5s", " "
if ($4=="c")
printf "%-5s\n", $5
else if ($6=="c")
printf "%-5s\n", $7
else
print ""
}
像awkscript你一樣保存chmod x awkscript然后運行:
$ ./awkscript tabfile
a x y c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
uj5u.com熱心網友回復:
input="\
13435 830169 830264 a 95 y 16
09433 835620 835672 x 46
30945 838405 838620 a 21 c 19
94853 850475 850660 y 15
04958 865700 865978 c 16 a 98
"
與awk:
printf '\t\t\ta\tx\ty\tc\n'
echo -n "$input" |
awk -v vars='a x y c' '
BEGIN {NV = split(vars,V)}
{
s = $1 "\t" $2 "\t" $3;
delete a;
for(i = 4; i < NF; i = i 2) a[$i] = $(i 1);
for(i = 1; i <= NV; i ) s = s "\t" a[V[i]];
print s
}
'
與紅寶石:
printf '\t\t\ta\tx\ty\tc\n'
echo -n "$input" |
vars='a x y c' ruby -ane '
BEGIN{v = ENV["vars"].split};
h = Hash[*$F[3..-1]];
puts $F[0..2].concat(v.map{|v| h[v]}).join("\t")
'
輸出:
a x y c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
uj5u.com熱心網友回復:
在perl:
$ perl -lane '
BEGIN { print join("\t", "", "", "", "a", "x", "y", "c"); }
my %vars = @F[3..$#F];
print join("\t", @F[0..2], @vars{qw/a x y c/});
' input.tsv
a x y c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
第四列和后面的所有列都作為哈希表的鍵/值對,然后按照正確的順序提取其中存在的變數值,以及前三列。大量使用切片。
uj5u.com熱心網友回復:
這是一個 awk 來做到這一點:
awk '
BEGIN{fmt="%s\t%s\t%s\t%s\t%s\t%s\t%s\n"}
NR==FNR{if ($4 && !($4 in seen)) {
seen[$4]= col; cols[col]=$4
}
if ($6 && !($6 in seen)) {
seen[$6]= col; cols[col]=$6
}
next
}
FNR==1{printf fmt, "\t","\t","\t",cols[1],cols[2],cols[3],cols[4]}
{ split("",fields)
fields[seen[$4]]=$5; fields[seen[$6]]=$7
printf fmt, $1,$2,$3,fields[1],fields[2],fields[3],fields[4]
}
' file file
這將找到變數名稱并按照第一次看到的順序列印它們。
印刷:
a y x c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
如果您事先知道您的變數并想說明列的順序,您可以執行以下操作:
awk '
BEGIN{
fmt="%s\t%s\t%s\t%s\t%s\t%s\t%s\n"
seen["a"]=1;seen["x"]=2;seen["y"]=3;seen["c"]=4
}
FNR==1{printf fmt, "\t","\t","\t","a","x","y","c"}
{ split("",fields)
fields[seen[$4]]=$5; fields[seen[$6]]=$7
printf fmt, $1,$2,$3,fields[1],fields[2],fields[3],fields[4]
}
' file
印刷:
a x y c
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
uj5u.com熱心網友回復:
假設:
- 四個變數名稱(
a/c/x/y在示例輸入中)事先未知 - 變數后面總是有一個非空值
- 變數/值對的數量(在單個輸入行上)事先未知
- OP 可以按字母順序列印變數列(OP 所需的輸出未指定是否/如何對四個變數列進行排序)
- 行的順序保持不變(輸入順序 == 輸出順序)
- 主機有足夠的記憶體來將整個輸入檔案保存在記憶體中(通過
awk陣列);這允許輸入檔案的單次傳遞;如果記憶體是一個問題(即,輸入檔案無法放入記憶體中),則需要不同的編碼/設計(本答案中未解決)
另一個awk想法......需要GNU awk使用多維陣列以及PROCINFO["sorted_in"]構造:
awk '
BEGIN { FS=OFS="\t" } # input/output field delimiters = <tab>
{ first3[FNR]=$1 OFS $2 OFS $3 # store first 3 fields
for (i=4;i<=NF;i=i 2) { # loop through rest of fields, 2 at a time
vars[$i] # keep track of variable names
values[FNR][$i]=$(i 1) # store the value for this line/variable combo
}
}
END { PROCINFO["sorted_in"]="@ind_str_asc" # sort vars[] indexes in ascending order
printf "%s%s", OFS, OFS # start printing header line ...
for (v in vars) # loop through variable names ...
printf "%s%s", OFS, v # printing to header line
printf "\n" # terminate header line
for (i=1;i<=FNR;i ) { # loop through our set of lines ...
printf "%s",first3[i] # print the 1st 3 fields and then ...
for (v in vars) # loop through list of all variables ...
printf "%s%s",OFS,values[i][v] # printing the associated value; non-existent values default to the empty string ""
printf "\n" # terminate the current line of output
}
}
' inputfile
注意:此設計允許處理可變數量的變數。
出于演示目的,我們將使用以下制表符分隔的輸入檔案:
$ cat input4 # OP's sample input file w/ 4 variables
13435 830169 830264 a 95 y 16
09433 835620 835672 x 46
30945 838405 838620 a 21 c 19
94853 850475 850660 y 15
04958 865700 865978 c 16 a 98
$ cat input6 # 2 additional variables added to OP's original input file
13435 830169 830264 a 95 y 16
09433 835620 835672 x 46 t 375
30945 838405 838620 a 21 c 19
94853 850475 850660 y 15 j 127 t 453
04958 865700 865978 c 16 a 98
通過awk腳本運行這些會生成:
############# input4
a c x y
13435 830169 830264 95 16
09433 835620 835672 46
30945 838405 838620 21 19
94853 850475 850660 15
04958 865700 865978 98 16
############# input6
a c j t x y
13435 830169 830264 95 16
09433 835620 835672 375 46
30945 838405 838620 21 19
94853 850475 850660 127 453 15
04958 865700 865978 98 16
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/373441.html
