我有 4466 個具有這種結構的 .tsv 檔案: file_structure
我想比較 4466 個檔案以查看有多少個 ID(第一列)匹配。我只找到了帶有“comm”的兩個檔案的 bash 命令。你能告訴我我該怎么做嗎?
謝謝
uj5u.com熱心網友回復:
我將您的問題讀為:
在所有 TSV 檔案中,每個檔案中都有哪些列 ID?
如果這是真的,我們想要來自所有檔案的所有列 ID 集的交集。我們可以使用join命令來得到任意兩個檔案的交集,我們可以使用交集的代數性質來有效地連接所有檔案。
考慮這三個檔案的 ID 的交集:
file1.tsv file2.tsv file3.tsv
--------- --------- ---------
ID ID ID
1 1 2
2 3 3
3
“3”是所有三個共享的唯一 ID。我們一次只能將兩個檔案連接在一起,因此我們需要一些方法來有效地獲取join (join file1.tsv file2.tsv) file3.tsv. 對我們來說幸運的是,交集是冪等的和關聯的,所以我們可以在所有檔案的回圈中迭代地應用連接,如下所示:
# "Prime" the common file
cp file1.tsv common.tsv
for TSV in file*.tsv; do
join "$TSV" common.tsv > myTmp
mv myTmp common.tsv
echo "After joining $TSV, common IDs are:"
cat common.tsv
done
當我運行它時,它會列印以下內容:
After joining file1.tsv, common IDs are:
ID
1
2
3
After joining file2.tsv, common IDs are:
ID
1
3
After joining file3.tsv, common IDs are:
ID
3
- 第一次迭代將 file1 與自身連接起來(因為我們與 file1 共同啟動);這是我們相交的地方是冪等的
- 第二次迭代加入file2,去掉ID“2”
- 第三次迭代加入 file3,將 ID 縮減為“3”
從技術上講,join 將字串“ID”視為要評估的內容之一......它不知道標題行是什么,或者 ID 是什么......它只知道查看一些常見值的欄位。在那個例子中,我們沒有指定一個欄位,所以它默認為第一個欄位,它總是找到“ID”,它總是找到“3”。
對于您的檔案,我們需要告訴 join:
- 在制表符上分隔,使用 -t <TAB-CHAR>
- 僅輸出連接欄位(默認情況下,它是第一個欄位),使用 -o 0
這是我的完整實作:
#!/bin/sh
TAB="$(printf '\t')"
# myJoin joins tsvX with the previously-joined common on
# the first field of both files; saving the the first field
# of the joined output back into common
myJoin() {
tsvX="$1"
join -t "$TAB" -o 0 common.tsv "$tsvX" > myTmp.tsv
mv myTmp.tsv common.tsv
}
# "Prime" common
cp input1.tsv common.tsv
for TSV in input*.tsv; do
myJoin "$TSV"
done
echo "The common IDs are:"
tail -n -1 common.tsv
有關原因的解釋"$(printf '\t')",請查看以下 POSIX 合規性:
- https://www.shellcheck.net/wiki/SC3003
- https://unix.stackexchange.com/a/468048/366399
uj5u.com熱心網友回復:
這個問題聽起來很模糊。因此,假設您要提取所有4466 個檔案共有的ID,即它們中的每一個在所有檔案中至少出現一次的ID ,您可以在純 Bash 中使用關聯陣列并計算“在它們上設定交叉點。*.tsv
#!/bin/bash
# removes all IDs from array $1 that do not occur in array $2.
intersect_ids() {
local -n acc="$1"
local -rn operand="$2"
local id
for id in "${!acc[@]}"; do
((operand["$id"])) || unset "acc['${id}']"
done
}
# prints IDs that occur in all files called *.tsv in directory $1.
get_ids_intersection() (
shopt -s nullglob
local -ar files=("${1}/"*.tsv)
local -Ai common_ids next_ids
local file id _
if ((${#files[@]})); then
while read -r id _; do (( common_ids["$id"])); done < "${files[0]}"
for file in "${files[@]:1}"; do
while read -r id _; do (( next_ids["$id"])); done < "$file"
intersect_ids common_ids next_ids
next_ids=()
done
fi
for id in "${!common_ids[@]}"; do printf '%s\n' "$id"; done
)
get_ids_intersection /directory/where/tsv/files/are
uj5u.com熱心網友回復:
假設您說“有多少個 ID(第一列)匹配”意味著您想找出這些檔案中哪些 ID 重復了行。
試試rq(https://github.com/fuyuncat/rquery/releases),一個簡單的命令列就可以做到。
[ rquery]$ ./rq -q "p d/\t/ | s @1, count(1) | g @1 | e @2>1" samples/*.tsv
M00002 3
M00003 2
M00006 2
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/520095.html
