![다양한 열을 기준으로 데이터 비교](https://linux55.com/image/166878/%EB%8B%A4%EC%96%91%ED%95%9C%20%EC%97%B4%EC%9D%84%20%EA%B8%B0%EC%A4%80%EC%9C%BC%EB%A1%9C%20%EB%8D%B0%EC%9D%B4%ED%84%B0%20%EB%B9%84%EA%B5%90.png)
열 수가 다른 행을 포함하는 파일(탭으로 구분)이 있습니다. 이와 같이:
Bin_37:_Pelotomaculum_sp._DTU098 GH3 GH57 GH15 GH18 GT2 GT4 GT28
Bin_45_1:_Thiopseudomonas_denitrificans GH3 GH57 GT2 GT9 CBM48
...
내 질문은 데이터가 구성된 열별 행 비교가 포함된 다른 파일(tsv)을 생성하는 방법입니다. 예를 들어 다음과 같이 누락된 값이 채워집니다.
Bin_37:_Pelotomaculum_sp._DTU098 GH3 GH57 GH15 GH18 GT2 GT4 GT28 NA NA
Bin_45_1:_Thiopseudomonas_denitrificans GH3 GH57 NA NA GT2 NA NA GT9 CBM48
...
답변1
매우 큰 파일에는 가장 효율적이지는 않지만 작동하는 버전일 수 있습니다.
입력하다파일 파일 1:
Bin_37:_Pelotomaculum_sp._DTU098 GH3 GH57 GH15 GH18 GT2 GT4 GT28
Bin_45_1:_Thiopseudomonas_denitrificans GH3 GH57 GT2 GT9 CBM48
Bin_99:_to_make_sure_no_columns_is_ok
스크립트(/bin/sh 또는 /bin/bash):
#!/bin/sh
F="file1";
COLS=$(cat "${F}"|sed 's/^[^\t]*//g;s/\t/\n/g'|sort|uniq|xargs);
# list of all available unique columns in SORTED order
echo "All avaiulable columns: [${COLS}]";
echo
# reading from the file line by line
cat "${F}"|while read L; do
# assign to A the first column
A=$(echo "${L}"|cut -d' ' -f1);
# if A is not empty
[ -n "${A}" ] &&
{
# take one by one all possible column values
for C in ${COLS}; do
# if the taken line has such column, add it to A,
# otherwise add to A NA
echo "${L} "|grep "\s${C}\s" >/dev/null &&
A="$A"$'\t'"${C}" ||
A="$A"$'\tNA';
done;
# print result line
echo "${A}";
};
done
산출:
All avaiulable columns: [CBM48 GH15 GH18 GH3 GH57 GT2 GT28 GT4 GT9]
Bin_37:_Pelotomaculum_sp._DTU098 NA GH15 GH18 GH3 GH57 GT2 GT28 GT4 NA
Bin_45_1:_Thiopseudomonas_denitrificans CBM48 NA NA GH3 GH57 GT2 NA NA GT9
Bin_99:_to_make_sure_no_columns_is_ok NA NA NA NA NA NA NA NA NA
같은(처음에는 사용 가능한 열 목록이 없습니다)라이너로서:
F="file1"; COLS=$(cat "${F}"|sed 's/^[^\t]*//g;s/\t/\n/g'|sort|uniq|xargs); cat "${F}"|while read L; do A=$(echo "${L}"|cut -d' ' -f1); [ -n "${A}" ] && { for C in ${COLS}; do echo "${L} "|grep "\s${C}\s" >/dev/null && A="$A"$'\t'"${C}" || A="$A"$'\tNA'; done; echo "${A}"; }; done
고쳐 쓰다. 보다 효율적인 버전 최적화, 주석의 제안을 기반으로 합니다(/bin/bash 필요).
F="file1"; IFS=$'\n'; COLS=($(sed 's/^[^\t]*//g;s/\t/\n/g' "${F}"|sort -u)); while read -r L; do A="${L%%$'\t'*}"; [ -n "${A}" ] && for C in ${COLS[@]}; do [[ "${L}"$'\t' == *$'\t'"${C}"$'\t'* ]] && A="$A"$'\t'"${C}" || A="$A"$'\tNA'; done && echo "${A}"; done <${F}; IFS=' '
답변2
지금까지의 다른 모든 답변과 마찬가지로 제공된 입력에서 제공하는 예상 출력이 생성되지 않지만 입력에 실제로 탭으로 구분된 빈 필드가 포함되어 있으면 NA
해당 필드가 s로 채워집니다.
$ cat tst.awk
BEGIN { FS=OFS="\t" }
NR == FNR {
gsub(/\t+$/,"")
maxNF = (NF>maxNF ? NF : maxNF)
next
}
{
for (i=1; i<=maxNF; i++) {
printf "%s%s", ($i == "" ? "NA" : $i), (i < maxNF ? OFS : ORS)
}
}
$ awk -f tst.awk file file
Bin_37:_Pelotomaculum_sp._DTU098 GH3 GH57 GH15 GH18 GT2 GT4 GT28
Bin_45_1:_Thiopseudomonas_denitrificans GH3 GH57 GT2 GT9 CBM48 NA NA
답변3
입력 파일이 탭으로 구분된 경우 다음 GNU awk 스크립트를 사용할 수 있습니다.
awk 'BEGIN{RS="[\t\n]"} !NF{$1="NA"} {printf "%s%s", $0, RT}' file
레코드 구분 기호는 의 RS
필드 수를 가져오기 위해 탭 또는 줄바꿈으로 설정됩니다 NF
.
비어 있으면 NF
(두 탭 사이에 단어가 없음을 의미) NA
문자열이 추가됩니다.
스크립트는 레코드 종결자 RT
(a \t
또는 a )를 사용하여 \n
결과 레코드를 인쇄합니다 .