Как объединить два файла с другим количеством строк в оболочке?

ls -dlp *2010* было бы хорошее начало к решению, но оно зависит, на что Вы хотите, чтобы вывод был похож.

7
14.07.2015, 15:32
4 ответа

Со справкой из этого ответа

awk 'FNR==NR && FNR>1 {a[$2] = $5; next}
     FNR > 1 && ($2 in a) && $3 == "ALL" {
         print $1 "    " $2 "    "  a[$2] "    "  $9
     }' file2 file1

Для получения заголовка также просто добавьте это к началу сценария:

 BEGIN{print "CHR SNP MAF P"}

Объяснение:

В первую очередь, когда два файла передаются awk, они обрабатываются один за другим. Существует две переменные, важные здесь: NR номер строки с начала awk команда, и FNR номер строки с начала текущего файла. Таким образом, когда первый файл обрабатывается (здесь file2), NR и FNR имейте то же значение, которое является значением строки, в настоящее время обрабатываемой. Но когда awk передают второму файлу, FNR сбрасывается к 1, так, чтобы NR и FNR больше не то же. Так, чтобы тест FNR==NR прием для знания, если обработанный файл является первым или нет.

Поэтому давайте см. код. Условие FNR==NR && FNR>1 тесты, обрабатываем ли мы первый файл а не первую строку. Если это имеет место, мы храним значение пятой колонны (MAF) в массиве, индексированном вторым (SNP) и затем next в заявлении говорится для передачи следующей строке.

Когда awk обрабатывает второй файл (который является file1), первый тест является ложью, так, чтобы awk попробовал второй тест: FNR > 1 && ($2 in a) && $3 == "ALL", это: не первая строка файла + второе значение столбца (SNP) существует в таблице a + третье значение столбца (TEST) "ALL". Если это имеет место, то это печатает столбец 1 (CHR) и два (SNP), добирается MAF значение от массива с a[$2], и затем столбец печати девять (P).

Добавление a BEGIN{...} оператор вначале добавляет команду, которая выполняется только, прежде чем первая строка обрабатывается.

6
27.01.2020, 20:15
  • 1
    Ну, если заголовки известны, можно добавить BEGIN{print "CHR SNP MAF P"} вначале. –  JPG 06.02.2014, 21:08
  • 2
    Май Вы смочь дать объяснение? Спасибо за Вашу отличную работу! –  Dadong Zhang 07.02.2014, 16:00

terdon упоминает, что делал его с coreutils только, скромным предложением:

(echo CHR SNP MAF P
 paste <(tail -n +2 file2) <(grep ALL file1) | 
   while read -r chr snp _ _ maf _ _ _ _ _ _ _ _ _ p; do 
     echo $chr $snp $maf $p; 
   done) | column -t

вывод:

CHR  SNP              MAF     P
0    AFFX-SNP-000541  NA      1
0    AFFX-SNP-002255  NA      1
1    rs12103          0.2894  0.5596
1    rs12103_1247494  0.2875  0.5581
5
27.01.2020, 20:15
  • 1
    +1 b/c является тайно моим любимым инструментом Unix. Это может даже предоставить Вам мир во всем мире при разрешении ему 8-) –  slm♦ 07.02.2014, 00:02
  • 2
    @slm - "b/c", что это? –  grebneke 07.02.2014, 10:00
  • 3
    @grebneke - b/c =, потому что –  slm♦ 07.02.2014, 10:01
  • 4
    @slm - спасибо, это отсортировано затем. Только мир во всем мире для движения и мы сделаны. достаточно ярмарка –  grebneke 07.02.2014, 10:03

Вот один способ сделать его (скопировать/вставить это непосредственно в Ваш терминал):

(
 awk -v OFS="\t" 'NR==1{print $1,$2,$5,"P"}' file2;
 awk '$3=="ALL"{print $2,$NF}' file1 | 
  while read snp p; do 
   awk -v snp="$snp" -v p=$p -v OFS="\t" '$2==snp{print $1,$2,$5,p}' file2;
  done
) > file3

Вывод похож на это:

CHR SNP MAF P
0   AFFX-SNP-000541 0   1
0   AFFX-SNP-002255 0   1
1   rs12103 C   0.5596
1   rs12103_1247494 C   0.5581

Примечания:

  • Я на 99% уверен, что можно сделать это так или иначе использование coreutils, возможно, комбинация sort,paste и join но я не мог понять это.
  • Это не эффективно и может требовать времени, если Вы имеете дело с огромными файлами.
  • Это изменяет разделителей полей на вкладки, удалите все случаи -v OFS="\t" если Вы не хотите это.
  • Как Вы видите, поля больше не выровненные. Так как они все разделяются вкладками, это не проблема ни для каких программ, которые считают файл, это - только проблема, при попытке считать его.

Объяснение

  • 1-е awk строка просто печатает 1-е, 2-е и 5-е поле заголовка файла 2, сопровождаемого P. Это - заголовок нового файла.
  • Второе awk печатает 2-е и последнее ($NF) поля каждой строки file1, где 3-е поле ALL.
  • Это затем передается через оболочку while цикл, который читает эти два поля в переменные $snp и $p.
  • Они затем даны последнему awk использование -v опция и затем, для каждой строки file2, если второе поле $snp, это печатает поля 1,2,5 и текущее значение $p.

Вот сценарий жемчуга, который делает то же:

perl -le 'print "CHR\tSNP\tMAF\tP"; open($f1, "$ARGV[0]"); 
          while(<$f1>){
           s/^\s+//; @f=split(/\s+/); $k{$f[1]}=$f[$#f] if $f[2] eq "ALL"
          } 
          open($f2,"$ARGV[1]"); 
          while(<$f2>){
            s/^\s+//; @f=split(/\s+/); 
            next unless defined($k{$f[1]}); 
            print "$f[0]\t$f[1]\t$f[4]\t$k{$f[1]}"
          }' file1 file2
4
27.01.2020, 20:15

Вот еще один способ:

{ printf %s\\n "CHR SNP MAF P"; grep -F ALL file1 | sort -k2,2 | \
join -j2 -o 2.1,2.2,2.5,1.9 - <(sort -k2,2 file2); } | column -t

вывод:

CHR  SNP              MAF     P
0    AFFX-SNP-000541  NA      1
0    AFFX-SNP-002255  NA      1
1    rs12103          0.2894  0.5596
1    rs12103_1247494  0.2875  0.5581

как это работает:

grep -F ВСЕ ФАЙЛ1 | сортирует -k2 печатает строки, соответствующие строке ALL, затем сортируетed на 2-ом поле: Затем

   0         AFFX-SNP-000541      ALL    0    0                0/0/0      nan      nan            1
   0         AFFX-SNP-002255      ALL    0    0                0/0/0      nan      nan            1
   1         rs12103_1247494      ALL    C    T           55/250/321   0.3994   0.4097       0.5581
   1                 rs12103      ALL    C    T           55/250/317   0.4019   0.4113       0.5596

соединяется во 2-ом поле (-j2) со строкой file2 (также отсортированной во 2-ом поле) с помощью -o 2. 1,2.2,2.5,1.9 для вывода 1-го, 2-го и 5-го полей из файла2 и 9-го полей из обработанного файла1:

0 AFFX-SNP-000541 NA 1
0 AFFX-SNP-002255 NA 1
1 rs12103 0.2894 0.5596
1 rs12103_1247494 0.2875 0.5581

Так как это было сгруппировано {...} с помощью printf %s\\n "CHR SNP MAF P", который печатает заголовок, то весь вывод затем претендует на столбец -t.
Обратите внимание, что при таком решении порядок строк (из файла2) в выводе не сохраняется. Просто бывает, что ваш файл2 уже отсортирован по 2-му полю, но если бы это было не так, например:

CHR                     SNP   A1   A2          MAF  NCHROBS
   0         AFFX-SNP-000541    0    0           NA        0
   1                 rs12103    C    T       0.2894     1244
   0         AFFX-SNP-002255    0    0           NA        0
   1         rs12103_1247494    C    T       0.2875     1252

и если бы вы хотели сохранить порядок строк, вы могли бы пронумеровать строки в file2 с помощью nl -ba -nrz file2:

000001  CHR                     SNP   A1   A2          MAF  NCHROBS
000002     0         AFFX-SNP-000541    0    0           NA        0
000003     1                 rs12103    C    T       0.2894     1244
000004     0         AFFX-SNP-002255    0    0           NA        0
000005     1         rs12103_1247494    C    T       0.2875     1252

перед сортировкой и присоединением и настроить команду: join on 2-е поле (обработанного) файла1 и 3-е поле (обработанного) файла2 и вывести поле номера строк + те же самые поля, что и первое решение join -1 2 -2 3 -o 2. 1,2.2,2.3,2.6,1. 9 затем повторно сортируйте вывод с помощью сортируйте -k1n и удалите первое поле с помощью разрезайте -d'' -f2- перед тем, как соединить весь вывод со столбцом -t:

{ printf %s\\n "CHR SNP MAF P"; grep -F ALL file1 | sort -k2,2 | join \
-1 2 -2 3 -o 2.1,2.2,2.3,2.6,1.9 - <(sort -k3,3 <(nl -ba -nrz file2)) | \
sort -k1n | cut -d' ' -f2-; } | column -t

вывод:

CHR  SNP              MAF     P
0    AFFX-SNP-000541  NA      1
1    rs12103          0.2894  0.5596
0    AFFX-SNP-002255  NA      1
1    rs12103_1247494  0.2875  0.5581

Обратите внимание, что оба решения предполагают, что в каждой строке встречается только одно ALL, а именно 3-е поле (отсюда и grep -F ALL). Если это не так, то для фильтрации только соответствующих строк придется использовать регресс.

1
27.01.2020, 20:15

Теги

Похожие вопросы