ファイルが多く、1列の共通IDを使用してファイルをマージしたいと思います。
ファイル1:
MYORGANISM_I_05140.t1 Atypical/PIKK/FRAP
MYORGANISM_I_06518.t1 CAMK/MLCK
MYORGANISM_I_00854.t1 TK-assoc/SH2/SH2-R
MYORGANISM_I_12755.t1 TK-assoc/SH2/Unique
ファイル2:
MYORGANISM_I_05140.t1 VALUES to be taken
MYORGANISM_I_12766.t1 what
ファイル3:
MYORGANISM_I_16941.t1 OK
MYORGANISM_I_93484.t1 LET IT BE
多くのファイルをマージして値が欠落している場合は、「-NA-」を追加したいと思います。希望の出力は次のとおりです。
MYORGANISM_I_05140.t1 Atypical/PIKK/FRAP VALUES to be taken -NA-
MYORGANISM_I_06518.t1 CAMK/MLCK -NA- -NA-
MYORGANISM_I_00854.t1 TK-assoc/SH2/SH2-R -NA- -NA-
MYORGANISM_I_12755.t1 TK-assoc/SH2/Unique -NA- -NA-
MYORGANISM_I_12766.t1 -NA- what -NA-
MYORGANISM_I_16941.t1 -NA- -NA- OK
MYORGANISM_I_93484.t1 -NA- -NA- LET IT BE
答え1
単一のツールでは不可能かもしれません。これはsort
、2つの一時的な外部ファイル呼び出しに関連するスクリプトベースの提案です。
#!/bin/bash
# The number of columns is equal to the number of input files, which is
# equal to the number of command-line arguments.
NUMCOLS=$#
# Use associative container to record all "IDs" and associated fields
declare -A entries
col=0
# Read the fields from all files and store them so that the field values can be
# associated with the file they came from (= the column they belong).
for FILE in "$@"
do
while read id value
do
SORTKEY="$id"__"$col"
entries[$SORTKEY]="$value"
echo "$id" >> "tmp.ids"
done < $FILE
let col=$col+1
done
# Sort the IDs
sort -u "tmp.ids" > "tmp.ids.sorted"
# Read the sorted IDs back in and generate output lines, where the
# column fields are taken from the associative container "entries" and
# tab-separated.
# If "entries" doesn't contain a value for a given key, output "-NA-" instead.
while read id
do
LINE="$id"
for (( col=0; col<NUMCOLS; col++ ))
do
SORTKEY="$id"__"$col"
if [[ -z "${entries[$SORTKEY]}" ]]
then
LINE=$(printf "%s\t-NA-" "$LINE")
else
LINE=$(printf "%s\t%s" "$LINE" "${entries[$SORTKEY]}")
fi
done
echo "$LINE" >> "outfile.txt"
done < "tmp.ids.sorted"
rm tmp.ids tmp.ids.sorted
これを呼び出すことができます./sortscript.sh <file1> <file2> ... <fileN>
。
これにより、関連コンテナが作成され、entries
「ID」フィールドと列番号で生成されたキーの下に入力ファイルから読み取られたすべてのフィールドが保存されます。 IDはソートできるように外部ファイルに書き込まれます。tmp.ids
これは必要に応じて表示されます。
ソート後にIDを再読み込みします。次に、各IDについて、コンテナはそのキーに属するすべての利用可能なフィールドを読み取り、entries
出力行(変数LINE
)に配置します。特定のID /列の組み合わせに使用できる値がない場合は、-NA-
代わりに作成してください。
その後、出力行がファイルに書き込まれますoutfile.txt
。
答え2
このjoin
ユーティリティを2回使用して、3つのファイルに対して2つの「外部結合」を作成できます。 3つのファイルがすべてタブで区切られているとし、最初の2つのファイルから始めます。
$ join -a 1 -a 2 -o 0,1.2,2.2 -e '-NA-' -t $'\t' <( sort File1 ) <( sort File2 )
MYORGANISM_I_05140.t1 Atypical/PIKK/FRAP VALUES to be taken
MYORGANISM_I_06518.t1 CAMK/MLCK -NA-
MYORGANISM_I_00854.t1 TK-assoc/SH2/SH2-R -NA-
MYORGANISM_I_12755.t1 TK-assoc/SH2/Unique -NA-
MYORGANISM_I_12766.t1 -NA- what
これを行うには、join
ユーティリティは最初のフィールド(デフォルト)でソートされたファイルを結合する必要があります。-a 1 -a2
一致しない場合でも、両方のファイルからすべての行を明示的に取得したいと思い、出力に-o 0,1.2,2.2
各ファイルの結合フィールド(最初の列)と2番目の列を含めるように要求します。この-e '-NA-'
オプションは、空のフィールドを埋めるために使用する文字列を指定します。
上記は、3番目のファイルへの2番目の接続で使用できる新しいデータセットを提供します。単純化のために上記の結果をtmpdata
使用できるとします(リダイレクト後)。
$ join -a 1 -a 2 -o 0,1.2,1.3,2.2 -e '-NA-' -t $'\t' tmpdata <( sort FILE3 )
MYORGANISM_I_00854.t1 TK-assoc/SH2/SH2-R -NA- -NA-
MYORGANISM_I_05140.t1 Atypical/PIKK/FRAP VALUES to be taken -NA-
MYORGANISM_I_06518.t1 CAMK/MLCK -NA- -NA-
MYORGANISM_I_12755.t1 TK-assoc/SH2/Unique -NA- -NA-
MYORGANISM_I_12766.t1 -NA- what -NA-
MYORGANISM_I_16941.t1 -NA- -NA- OK
MYORGANISM_I_93484.t1 -NA- -NA- LET IT BE
これは以前の「外部結合」をある程度繰り返すが、-o
オプションの追加列も追加します。
答え3
シェル(/bin/shまたは/bin/bash)で実行されるコード行:
FILES="File1 File2 FILE3"; LIST=$(for F in ${FILES}; do cat ${F}|awk '{print $1}'; done|sort|uniq|xargs); for i in ${LIST}; do echo -n "$i"; for F in ${FILES}; do L=$(grep "^${i}\s" ${F}|head -1|sed 's/\t/ /'|cut -d' ' -f 2-|sed 's/^\s*//g'); [ -z "${L}" ] && echo -n " -NA-" || echo -n " ${L}" ; done; echo; done|sort
出力:
MYORGANISM_I_00854.t1 TK-assoc/SH2/SH2-R -NA- -NA-
MYORGANISM_I_05140.t1 Atypical/PIKK/FRAP VALUES to be taken -NA-
MYORGANISM_I_06518.t1 CAMK/MLCK -NA- -NA-
MYORGANISM_I_12755.t1 TK-assoc/SH2/Unique -NA- -NA-
MYORGANISM_I_12766.t1 -NA- what -NA-
MYORGANISM_I_16941.t1 -NA- -NA- OK
MYORGANISM_I_93484.t1 -NA- -NA- LET IT BE
説明する:
# create list of files
# it can be created based on search like
# find . -type f -name filename.txt
# or something different
FILES="File1 File2 FILE3";
# create a list if unique first lines from all files from the list FILES
LIST=$(for F in ${FILES}; do cat ${F}|awk '{print $1}'; done|sort|uniq|xargs);
# take one by one each first line
# and go through all the files find corresponding lines endings
# and put them together
# or take '-NA-' for non-existing
for i in ${LIST}; do
echo -n "$i";
for F in ${FILES}; do
#
# old version of line commented out
# L=$(grep "^${i}\s" ${F}|head -1|cut -d' ' -f 2-|sed 's/^\s*//g');
# new version of line to make tab separator working
L=$(grep "^${i}\s" ${F}|head -1|sed 's/\t/ /'|cut -d' ' -f 2-|sed 's/^\s*//g');
#
[ -z "${L}" ] && echo -n " -NA-" || echo -n " ${L}" ;
done;
echo;
done|sort
# sorted results printed