Bashdagi fayllarni solishtirish uchun tezroq hal

file1:

chr1    14361   14829   NR_024540_0_r_DDX11L1,WASH7P_468
chr1    14969   15038   NR_024540_1_r_WASH7P_69
chr1    15795   15947   NR_024540_2_r_WASH7P_152
chr1    16606   16765   NR_024540_3_r_WASH7P_15
chr1    16857   17055   NR_024540_4_r_WASH7P_198

va file2:

NR_024540 11

I need find match file2 in file1 and print whole file1 + second column of file2

Shunday qilib, ouptut:

  chr1  14361   14829   NR_024540_0_r_DDX11L1,WASH7P_468 11
chr1    14969   15038   NR_024540_1_r_WASH7P_69 11
chr1    15795   15947   NR_024540_2_r_WASH7P_152 11
chr1    16606   16765   NR_024540_3_r_WASH7P_15 11
chr1    16857   17055   NR_024540_4_r_WASH7P_198 11

Mening yechimim boshida juda sekin:

#!/bin/bash

while read line; do

c=$(echo $line | awk '{print $1}')
d=$(echo $line | awk '{print $2}')

grep $c file1 | awk -v line="$d" -v OFS="\t" '{print $1,$2,$3,$4"_"line}' >> output


 done < file2

Men har qanday bash yoki awk echimini tezroq afzal qilaman. Chiqish o'zgartirilishi mumkin, ammo barcha ma'lumotlarni saqlab qolish kerak (ustun buyurtmasi boshqacha bo'lishi mumkin).

EDIT:

Hozircha @chepnerga ko'ra eng tezkor echimga o'xshaydi:

#!/bin/bash

while read -r c d; do

grep $c file1 | awk -v line="$d" -v OFS="\t" '{print $1,$2,$3,$4"_"line}' 

done < file2 > output
2
@Jorge - bu yechimni sinab ko'rsata olasizmi va menga ishlashni bildiring - stackoverflow.com/questions/42509226/…
qo'shib qo'ydi muallif VIPIN KUMAR, manba
@Geroge, sqlite.org , engil indekslangan ma'lumotlar bazasini topish nuqtai nazaridan boshlash uchun yaxshi joy bo'lishi mumkin. matnli faylni skanerlashdan ancha tezroq qo'ng'iroqlarni amalga oshirishga qodir.
qo'shib qo'ydi muallif Charles Duffy, manba
Ma'lumotlaringizni so'rovni qo'llab-quvvatlash uchun ma'lumotlaringizni to'g'ri ma'lumotlar bazasida saqlash eng tezkor bo'ladi.
qo'shib qo'ydi muallif chepner, manba
@Geroge: raqamlar file1 ichida yoki faqat oxirgi so'zi ostida paydo bo'lishi mumkin?
qo'shib qo'ydi muallif Inian, manba
Biron bir tarzda file1 yoki/va file2 tartiblanganmi?
qo'shib qo'ydi muallif Jose Ricardo Bustos M., manba
Ha, ular 1V, 2-k 2n, 2 ga binoan savollarga javob berishadi, lekin bu vazifani tartiblashtirish va o'z talablarim bo'yicha tartiblashtirish uchun muammo yo'q.
qo'shib qo'ydi muallif Geroge, manba
@chepner javob uchun rahmat. Men ma'lumotlar bazasi bilan ishlashni bilmayman .. Buni qanday qilishimni aytib bera olasizmi? Rahmat!
qo'shib qo'ydi muallif Geroge, manba
@Inian rahmat. Raqamlar har qanday joyda paydo bo'lishi mumkin. Keyinroq tuzataman.
qo'shib qo'ydi muallif Geroge, manba

7 javoblar

Bitta Awk buyrug'ida,

awk 'FNR==NR{map[$1]=$2; next}{ for (i in map) if($0 ~ i){$(NF+1)=map[i]; print; next}}' file2 file1

chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11
chr1 14969 15038 NR_024540_1_r_WASH7P_69 11
chr1 15795 15947 NR_024540_2_r_WASH7P_152 11
chr1 16606 16765 NR_024540_3_r_WASH7P_15 11
chr1 16857 17055 NR_024540_4_r_WASH7P_198 11

Multi-linerda yana o'qilishi mumkin bo'lgan versiya

FNR==NR {
    # map the values from 'file2' into the hash-map 'map'
    map[$1]=$2
    next
}
# On 'file1' do
{
    # Iterate through the array map
    for (i in map){
        # If there is a direct regex match on the line with the 
        # element from the hash-map, print it and append the 
        # hash-mapped value at last
        if($0 ~ i){
            $(NF+1)=map[i]
            print
            next
        }
    }
}
5
qo'shib qo'ydi
@JoseRicardoBustosM .: Siz bilan rozi bo'lasiz, ammo Ed Morton har qanday mos keladigan funksiyalar bo'yicha har doim to'g'ridan-to'g'ri ~ ni ishlatishni taklif qiladi
qo'shib qo'ydi muallif Inian, manba
@AkshayHegde Xosega oldingi izohda aytib o'tganimdek, sizning kalit qidiruvingiz kalitni aniq bir shaklda bo'lishini ta'kidlaydi. Mening regexlarim o'yinlari u barcha uchrashuvlar uchun biroz umumiy bo'ladi
qo'shib qo'ydi muallif Inian, manba
@AkshayHegde: Iltimos, buni amalga oshirish mumkin deb hisoblasangiz, iltimos, menikiga nisbatan tezroqroq yondashuvni joylashtiring
qo'shib qo'ydi muallif Inian, manba
@JoseRicardoBustosM .: Shuningdek, mening yagona tashvishim ma'lumotlarga tegishli, sizning kodingiz kodi _ bilan ajratilgan file2 dan ikki so'z bo'lsa, sizning namunangiz yaxshi ishlaydi, to'g'ridan-to'g'ri regex ma`ruza ham umumiy hisoblanadi, men noto'g'ri
qo'shib qo'ydi muallif Inian, manba
@Geroge: ishlatilishi mumkin bo'lgan minimalist awk .
qo'shib qo'ydi muallif Inian, manba
bosma dan so'ng keyingi iborasini qo'shing, > <1>
qo'shib qo'ydi muallif Akshay Hegde, manba
awk "FNR == NR {map [$ 1] = $ 2; Keyingi} {split ($ 4, d,/_ /); K = d [1] "_" d [2]} (xarita xarita) {print $ 0, xarita [k]} 'file2 file1 yoki hatto bu ajralishdan ko'ra yaxshiroq awk' FNR == NR {map [$ 1] = $ 2; Keyingi {} $ k = $ 4 "_" $ 5 (xarita xarita) {print $ 0, map [k]} 'file2 FS =' [_] + 'file1 . `
qo'shib qo'ydi muallif Akshay Hegde, manba
@Inian: Ooops! Ha, o'ng qanaqa mantiqiy yoki qisman o'yin bo'lsa, noqulayliklar uchun uzr so'raydi.
qo'shib qo'ydi muallif Akshay Hegde, manba
yaxshi split ($ 4, v, "_"); key = v [1] "_" v [2]; (agar siz xaritada) uchun o'rniga o'rniga
qo'shib qo'ydi muallif Jose Ricardo Bustos M., manba
@Geroge file2 qancha qator mavjud?
qo'shib qo'ydi muallif Jose Ricardo Bustos M., manba
@ File2 juda katta bo'lsa, unda for (i xaritada) asta-sekin .... bu fayl1da har bir qator uchun 56K iteratsiya .....
qo'shib qo'ydi muallif Jose Ricardo Bustos M., manba
@JoseRicardoBustosM. wc -l file1 600K va wc -l fayli2 56K
qo'shib qo'ydi muallif Geroge, manba
Juda ko'p rahmat, lekin hali ham sekinlashtirishi mumkin. Lekin awk-da yaxshi echim.
qo'shib qo'ydi muallif Geroge, manba

harakat qilib ko'ring -

 cat file2
NR_024540 11
NR_024541 12

 cat file11
chr1    14361   14829   NR_024540_0_r_DDX11L1,WASH7P_468
chr1    14361   14829   NR_024542_0_r_DDX11L1,WASH7P_468
chr1    14969   15038   NR_024540_1_r_WASH7P_69
chr1    15795   15947   NR_024540_2_r_WASH7P_152
chr1    16606   16765   NR_024540_3_r_WASH7P_15
chr1    16857   17055   NR_024540_4_r_WASH7P_198
chr1    14361   14829   NR_024540_0_r_DDX11L1,WASH7P_468
chr1    14969   15038   NR_024540_1_r_WASH7P_69
chr1    15795   15947   NR_024540_2_r_WASH7P_152
chr1    16606   16765   NR_024540_3_r_WASH7P_15


awk 'NR==FNR{a[$1]=$2;next} substr($4,1,9) in a {print $0,a[substr($4,1,9)]}' file2 file11
chr1    14361   14829   NR_024540_0_r_DDX11L1,WASH7P_468 11
chr1    14969   15038   NR_024540_1_r_WASH7P_69 11
chr1    15795   15947   NR_024540_2_r_WASH7P_152 11
chr1    16606   16765   NR_024540_3_r_WASH7P_15 11
chr1    16857   17055   NR_024540_4_r_WASH7P_198 11
chr1    14361   14829   NR_024540_0_r_DDX11L1,WASH7P_468 11
chr1    14969   15038   NR_024540_1_r_WASH7P_69 11
chr1    15795   15947   NR_024540_2_r_WASH7P_152 11
chr1    16606   16765   NR_024540_3_r_WASH7P_15 11

ishlash - (55000 yozuvlar uchun sinov qilingan)

time awk 'NR==FNR{a[$1]=$2;next} substr($4,1,9) in a {print $0,a[substr($4,1,9)]}' file2 file1 > output1

real    0m0.16s
user    0m0.14s
sys     0m0.01s
2
qo'shib qo'ydi
@AkshayHegde - Men bu savolning SO a'zolari tomonidan taqdim etilgan barcha echimlarni sinab ko'rdim va bu echimni eng kamida 60% kamroq vaqt topdim.
qo'shib qo'ydi muallif VIPIN KUMAR, manba
@AkshayHegde - Yangilangan javobni tekshiring va fikringizni bildiring.
qo'shib qo'ydi muallif VIPIN KUMAR, manba
Har bir inson, kamida ikki soniyadan farqli ravishda kamida bir marta o'z javobini yo'qotadi .... 15 daqiqada farq tasodif uchun ham katta. Barchamizga shunday bo'ldi.
qo'shib qo'ydi muallif George Vasiliou, manba
@VIPINKUMAR: buni ham sinab ko'ring awk »FNR == NR {map [$ 1] = $ 2; Keyingi {} {k = $ 4 "_" $ 5} (xarita xarita) {print $ 0, map [k]} 'file2 FS =' [_] + 'file1
qo'shib qo'ydi muallif Akshay Hegde, manba
@VIPINKUMAR: ^ 1 Endi uning yaxshi, (var qatorda) to'g'ri usuli
qo'shib qo'ydi muallif Akshay Hegde, manba

join va sed kodini ishlatib, file1 va file2

join <(sed -r 's/[^ _]+_[^_]+/& &/' file1) file2 -1 4 -2 1 -o "1.1 1.2 1.3 1.5 2.2" > output

If the output order doesn't matter, to use awk

awk 'FNR==NR{d[$1]=$2; next}
    {split($4,v,"_"); key=v[1]"_"v[2]; if(key in d) print $0, d[key]}
' file2 file1 

olasiz,

chr1 14361 14829 NR_024540_0_r_DDX11L1,WASH7P_468 11
chr1 14969 15038 NR_024540_1_r_WASH7P_69 11
chr1 15795 15947 NR_024540_2_r_WASH7P_152 11
chr1 16606 16765 NR_024540_3_r_WASH7P_15 11
chr1 16857 17055 NR_024540_4_r_WASH7P_198 11
2
qo'shib qo'ydi
yoki hatto bu awk 'FNR == NR {map [$ 1] = $ 2; Keyingi {} {k = $ 4 "_" $ 5} (xarita xarita) {print $ 0, map [k]} 'file2 FS =' [_] + 'file1
qo'shib qo'ydi muallif Akshay Hegde, manba
@Jose Thats ajoyib, awk hal tuyg'u kabi ishlaydi va juda ham tez! Rahmat!
qo'shib qo'ydi muallif Geroge, manba

Agar izlanuvchi mag'lub doim bir xil uzunlikda bo'lsa ( length ("NR_024540") == 9 ):

awk 'NR==FNR{a[$1]=$2;next} (i=substr($4,1,9)) && (i in a){print $0, a[i]}' file2 file1

Ta'riflangan:

NR==FNR {                         # process file2
    a[$1]=$2                      # hash record using $1 as the key
    next                          # skip to next record
} 
(i=substr($4,1,9)) && (i in a) {  # read the first 9 bytes of $4 to i and search in a
    print $0, a[i]                # output if found
}
1
qo'shib qo'ydi

Ko'p tashqi dasturlarni keraksiz boshlaysiz. read awk kodini ikki marta chaqirish o'rniga kirish kodini file2 dan ajratib turing. grep ni ishlatishning hojati yo'q; awk filtrlashni o'zi bajarishi mumkin.

while read -r c d; do
    awk -v field="$c" -v line="$d" -v OFS='\t' '$0 ~ field {print $1,$2,$3,$4"_"line}' file1
done < file2 > output
1
qo'shib qo'ydi
Afsuski: file oxirgi kodi awk bo'lishi kerak.
qo'shib qo'ydi muallif chepner, manba
rahmat ... Faylni qaerdan o'qiyman?
qo'shib qo'ydi muallif Geroge, manba
Sizga juda minnatdorman. Bilish juda yaxshi, o'qishni qanday ishlatish kerak? -D d :) Men o'ynab o'ynayapman, deb o'ylayman, sizning "o'qishingiz kerak" ... va mening grepim eng tezkor echimdir.
qo'shib qo'ydi muallif Geroge, manba

Hech qanday awk yoki sed kerak emas. Bu file2 faqat bitta qatorni ifodalaydi:

n="`cut -f 2 file2`" ; while read x ; do echo "$x $n" ; done < file1
0
qo'shib qo'ydi
awk -F '[[:blank:]_]+' '
   FNR==NR { a[$2]=$3 ;next }
   { if ( $5 in a ) $0 = $0 " " a[$5] }
   7
   ' file2 file1

Izoh:

  • use _ as extra field separator so file names are easier to compare in both file (using only the number part).
  • 7 is for fun, it's just a non 0 value -> print the line
  • i don't change the field (NF+1, ...) so we keep the original format adding just the referenced number

kichik kodni kodi (kodning hajmi uchun optimallashtirilgan) (fayl1da majburiy bo'lmagan bo'sh satrlarni nazarda tutgan holda). agar ajratgich faqat bo'sh joy bo'lsa, siz bo'sh joy bilan [: bo'sh:] joylashtirasiz

awk -F '[[:blank:]_]+' 'NF==3{a[$2]=$3;next}$0=$0" "a[$5]' file2 file1
0
qo'shib qo'ydi