Использование подстановочных знаков для элегантного преобразования тысяч файлов epub в mobi

Я бы сделал это на Perl, потому что в нем есть функция sort, которая позволяет нам легко рассматривать A Tи T Aкак одно и то же. Например, (показывает выходные данные для всех ваших примеров файлов вместе взятых):

$ perl -lane 'if(!$k){$name{join("","chr".$F[0],$F[3],sort($F[4],$F[5]))}=$F[1]; }else{$var=join("", "chr".$F[1],$F[2],sort($F[3],$F[4])); $F[0]=$name{$var} if $name{$var};print join "\t", @F; } $k++ if eof' file2 file1
SNP Chr Pos EA  NEA EAF Beta    SE  Pvalue  Neff
7:10100610_G_A  7   10100610    A   G   0.0002  0.13    0.58    8.2e-01 120658
7:10100610_G_C  7   10100610    C   G   0.0013  0.1 0.13    4.4e-01 139170
10:1006107_C_G  10  1006107 C   G   1   -0.11   0.42    7.9e-01 152016
1:79137_A_T 1   79137   A   T   0.25    -0.026  0.0073  4.0e-04 231420
1:79033_A_G 1   79033   A   G   0.0047  -0.038  0.056   4.9e-01 225429
1:118630_C_T    1   118630  C   T   0.99    -0.033  0.055   5.5e-01 226311
1:533179_A_G    1   533179  A   G   1   -0.098  0.19    6.1e-01 185906

Или, чуть более разборчиво:

$ perl -lane 'if(!$k){
                $name{join("","chr".$F[0],$F[3],sort($F[4],$F[5]))}=$F[1]; 
              }
              else{
                $var=join("", "chr".$F[1],$F[2],sort($F[3],$F[4])); 
                $F[0]=$name{$var} if $name{$var};
                print join "\t", @F; 
             } 
            $k++ if eof' file2 file1
SNP Chr Pos EA  NEA EAF Beta    SE  Pvalue  Neff
7:10100610_G_A  7   10100610    A   G   0.0002  0.13    0.58    8.2e-01 120658
7:10100610_G_C  7   10100610    C   G   0.0013  0.1 0.13    4.4e-01 139170
10:1006107_C_G  10  1006107 C   G   1   -0.11   0.42    7.9e-01 152016
1:79137_A_T 1   79137   A   T   0.25    -0.026  0.0073  4.0e-04 231420
1:79033_A_G 1   79033   A   G   0.0047  -0.038  0.056   4.9e-01 225429

Пояснение

  • perl -lane:-aзаставляет Perl вести себя как awk, автоматически разбивая входные данные на массив @Fпо пробелам. Поскольку массивы Perl начинаются с 0, $F[0]будет первым полем, $F[1]будет вторым и т. д. Поле N равно $F[N-1]. -nзаставляет perl читать свои аргументы как текстовые файлы и применять сценарий, заданный -e, к каждой их строке. -lпросто удаляет завершающие символы новой строки из каждой входной строки и добавляет новую строку к каждому вызову print.

  • $k++ if eof:это увеличивает переменную $kна 1, если мы достигли конца файла(eof). Затем мы можем использовать if(!$k)(, если $k не определен )как эквивалент NR==FNRв awk.

  • if (!$k ){$name{join ("","chr".$F[0],$F[3],sort ($F[4], $F[5] ))}=$F[1];} : if this is the first file,файл2 , join fields 1, 4, and the sorted fields 5 and 6, into a string and use that string as the key in the hash (associative array)имя . Then, save the variant's name from file2 as the value associated with that key. The sorting lets us treatAT andTA as equivalent. I use"chr".$F[0] to deal with cases like1 123 and11 23 `, где конкатенация хромосомы и положения дает одно и то же число, даже если хромосомы на самом деле разные.

  • else{:если мы сейчас читаем второй файл, file1.

  • $var=join("", $F[1],$F[2],sort($F[3],$F[4]));:построить ключ. На этот раз с использованием полей 2, 3 и сортировки 4 и 5.
  • $F[0]=$name{$var} if $name{$var};:установить 1-е поле на значение, хранящееся в хеше name, если есть значение для этого ключа. ifнеобходим, чтобы убедиться, что мы не меняем заголовок или какие-либо другие варианты, которые могут присутствовать в file1, но не в file2.
  • print join "\t", @F;:распечатать поля, включая только что внесенные изменения.
8
17.09.2021, 12:44
2 ответа

с помощью bash...

find. -name '*.epub' | xargs  basename -s.epub | xargs -I {} ebook-convert {}.epub {}.mobi ;

или, для имен файлов с пробелами...

find. -name '*.epub' -print0 | xargs -0 basename -s.epub | xargs -I {} ebook-convert "{}.epub" "{}.mobi" ;

ломая его...

find. -name '*.epub'

find. -name '*.epub' | xargs  basename -s.epub 

CMD='echo ebook-convert' && find. -name '*.epub' | xargs basename -s.epub | xargs -I {} $CMD "{}.epub" "{}.mobi" ;

опции -print0и -0заставляют эти команды использовать пустые значения вместо пробелов для разделения имен файлов.

-Iсоздает заполнитель {}, который работает путем замены.

Ps :хотя это полезная техника, я также думаю, что Makefile (см. выше )является отличным решением для такого рода задач.

3
18.09.2021, 00:38

Я думаю, что вы можете сделать так же мило, как %.mobi: %.epubиз GNU make часть принятого ответа --без GNU make и его ограничений на имена файлов --с небольшой оболочкой:

from_to(){
    sp=${1%%%*}; ss=${1#*%}; shift
    dp=${1%%%*}; ds=${1#*%}; shift
    for s in "$sp"*"$ss"; do
        d=${s#"$sp"}; d=$dp${d%"$ss"}$ds
        "$@" "$s" "$d" || exit 1
    done
}

Который можно использовать как

from_to %.epub %.mobi ebook-convert
from_to dir1/book_%.epub dir2/%.mobi ebook-convert

Пример пробного теста:

% touch {1,2,3}.foo
% from_to./%.foo bar/%.baz echo translate --
translate --./1.foo bar/1.baz
translate --./2.foo bar/2.baz
translate --./3.foo bar/3.baz

В любом случае, вы должны использовать что-то другое, кроме *, так как это имеет устоявшееся значение в оболочке Unix.

1
20.09.2021, 01:39

Теги

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