
次のようなファイルがあります:
OV2 OVI 1VI OV3 3VI
er 23 23 23 23 23
tr 24 24 24 24 24
名前に含まれる列とともに 1 列目を印刷しますVI
(どの列に文字列が含まれるかは事前にわかりません)。上記の例では、出力は次のようになります。
OVI 1VI 3VI
er 23 23 23
tr 24 24 24
すべての列はタブで区切る必要があります。
答え1
perl -lane '$,="\t";
$. == 1 and @A = grep $F[$_] =~ /VI/, 0..$#F;
print @F[0,@A];
' yourfile
結果
ID OVI 1VI 3VI
er 23 23 23
tr 24 24 24
働く
- 最初の行から、
$. == 1
文字列を含むフィールドのインデックスを抽出しますVI
。 - 配列 内のこれらのインデックスのリストを使用して、配列から
@A
最初のフィールドと配列にリストされているフィールドを切り出します。は に設定されています。YMMV。@A
@F
OFS=$,
TAB
awk
awk -v OFS="\t" '
NR==1{
for ( i=2; i<=NF; i++ )
if ( $i ~ /VI/ )
str = str OFS i
N = split(str, A, OFS)
}{
s = $1
for ( i=2; i<=N; i++ )
s = s OFS $(A[i])
$0 = s
}1
' yourfile
翻訳
sed -e '
# TAB->spc, multiple spc -> single spc, trim leading/trailing spc
y/ / /;s/[ ]\{2,\}/ /g;s/^[ ][ ]*//;s/[ ][ ]*$//
# only for first line, remove the first field and store remaining in hold area
1{
h
s/[ ]/\
/
s/.*\n//
x
}
# append hold area (which now has 2nd...last fields
# data of the first record) to the present line and
# place a marker at the end of the first field
G
s/[^ ][^ ]*[ ]/&\
/
# setup a do-while loop which progressively either keeps VI data or trims it
:loop
# 1 2 3
s/\(\n\)\([^ ][^ ]*\)[ ]\{0,1\}\(.*\n\)[^ ]*VI[^ ]*[ ]\{0,1\}/ \2\1\3/;tloop
s/\(\n\)[^ ][^ ]*[ ]\{0,1\}\(.*\n\)[^ ][^ ]*[ ]\{0,1\}/\1\2/
/\n\n$/!bloop
# loop ends when the two \ns collide at the end of line
# remove the two \ns and what remains is what you wanted
s///
' yourfile
答え2
awk解決:
awk 'BEGIN{FS="[\t ]+"; OFS="\t"}NR==1{for(i=2;i<=NF;i++)
{if($i~/VI/) a[i]; }}{r=$1; for(i in a) r=r OFS $i; print l}' file
出力:
OVI 1VI 3VI
er 23 23 23
tr 24 24 24
FS="[\t ]+"
- 入力フィールドセパレーターOFS="\t"
- 出力フィールドセパレーターNR==1
- 初めてヘッダラインif($i~/VI/) a[i]
- 一致する場合はフィールド番号をキャプチャするVI
r=$1; for(i in a) r=r OFS $i; print r
- 必要なフィールド番号を反復処理し、それぞれの値を出力する
順序が崩れる場合は、次の withasorti()
関数を使用します (配列をインデックスでソートするため)。
awk 'BEGIN{FS="[\t ]+"; OFS="\t"}NR==1{for(i=2;i<=NF;i++)
{if($i~/VI/) a[i]; }}{r=$1; asorti(a,b); for(i in b) {r=r OFS $(b[i])} print r}' file
答え3
Python スクリプト ソリューション。最初の行を解析し、列のリストを構築するという基本操作を行います。VI が含まれていない列は None に設定されます。他のすべての行は単語に分割され、比較のために列リスト項目とペアに結合されます。対応する列項目が None の場合、現在の行のその単語は印刷されません。それ以外の場合は、None ではないものが印刷されます。
#!/usr/bin/env python3
import sys
with open(sys.argv[1]) as fd:
indexes = []
for index,line in enumerate(fd):
if index == 0:
columns = line.strip().split()
for i,col in enumerate(columns):
if 'VI' in col or i == 0:
indexes.append(col)
else:
indexes.append(None)
for x in indexes:
if x:
print(x,end=" ")
print("")
continue
for j in zip(line.strip().split(),indexes):
if j[1]:
print(j[0],end=" ")
print("")
注:タブ区切りの出力にするにend=" "
は、 を置き換えます。end="\t"
テスト走行:
$ ./get_colums.py input.txt
ID OVI 1VI 3VI
er 23 23 23
tr 24 24 24