Изменить текст в аргументе для xargs (или GNU Parallel) - PullRequest
2 голосов
/ 13 марта 2012

У меня есть программа, которую я могу запустить двумя способами: односторонний или парный. Вот синтаксис:

program <output-directory-name> <input1> [input2]

Где требуется выходной каталог и хотя бы один вход. Если бы я хотел запустить это на трех файлах, скажем, образцах A, B и C, я бы использовал что-то вроде find с xargs или параллельным:

user@host:~/single$ ls
sampleA.txt  sampleB.txt  sampleC.txt

user@host:~/single$ find . -name "sample*" | xargs -i echo program {}-out {}
program ./sampleA.txt-out ./sampleA.txt
program ./sampleB.txt-out ./sampleB.txt
program ./sampleC.txt-out ./sampleC.txt

user@host:~/single$ find . -name "sample*" | parallel --dry-run program {}-out {}
program ./sampleA.txt-out ./sampleA.txt
program ./sampleB.txt-out ./sampleB.txt
program ./sampleC.txt-out ./sampleC.txt

Но когда я хочу запустить программу в режиме «парный конец», мне нужно дать ей два входа. Это связанные файлы, но их нельзя просто объединить - вы должны запустить программу с обоими в качестве входных данных. Файлы имеют разумные имена, например, sampleA_1.txt и sampleA_2.txt.

Я хочу, чтобы можно было легко создать это в командной строке с помощью чего-то вроде xargs (или, предпочтительно, параллельного):

user@host:~/paired$ ls
sampleA_1.txt  sampleB_1.txt  sampleC_1.txt
sampleA_2.txt  sampleB_2.txt  sampleC_2.txt

user@host:~/paired$ find . -name "sample*_1.txt" | sed/awk? | parallel ?
program ./sampleA-out ./sampleA_1.txt ./sampleA_2.txt
program ./sampleB-out ./sampleB_1.txt ./sampleB_2.txt
program ./sampleC-out ./sampleC_1.txt ./sampleC_2.txt

В идеале команда должна убрать _1.txt для создания имени выходного каталога (sampleA-out и т. Д.), Но мне действительно нужно иметь возможность взять этот аргумент и изменить _1 на _2 для второго ввода .

Я знаю, что это очень просто с помощью скрипта - я сделал это в Perl с быстрой заменой регулярных выражений. Но я бы хотел сделать это с помощью быстрого однострочного текста.

Заранее спасибо.

Ответы [ 4 ]

1 голос
/ 13 марта 2012

Я сделал это в Perl с быстрой заменой регулярного выражения.Но я бы хотел сделать это с быстрым однострочником.

В Perl тоже есть однострочные, как и у sed и awk.Вы можете написать:

find . -name "sample*_1.txt" | perl -pe 's/_1\.txt$//' | parallel program {}-out {}_1.txt {}_2.txt

(флаг -e означает «следующий аргумент - текст программы»; флаг -p означает «программа должна выполняться в цикле; для каждой строки ввода»установите $_ в эту строку, затем запустите программу и напечатайте $_ ".)

1 голос
/ 13 марта 2012

С sed и xargs вы можете сделать что-то вроде этого:

find . -name "sample*_1.txt" | sed -n 's/_1\..*$//;h;s/$/_out/p;g;s/$/_1.txt/p;g;s/$/_2.txt/p' | xargs -L 3 echo program

Т.е.: sed создает три аргумента, а xargs -L 3 составляет командные строки с тремя аргументами.

0 голосов
/ 15 марта 2012

Более короткая версия:

parallel --xapply program {1.}.out {1} {2} :::: <(ls *_1.txt) <(ls *_2.txt)

, но это работает, только если каждый _1.txt имеет соответствующий _2.txt и наоборот.

0 голосов
/ 13 марта 2012

Предполагая, что у вас всегда есть ровно 2 файла в вашем каталоге для каждой пары, и предположим, что они отсортированы правильно по find (это вы можете убедиться, передав результаты от find до sort), возможно xargs -l 2сделал бы работу.Это говорит xargs размещать 2 последовательных входящих параметра в каждой командной строке, которую он выполняет.

...