我有一个程序,可以用两种方式运行:单端或成对端模式。语法如下:
program <output-directory-name> <input1> [input2]
其中需要输出目录和至少一个输入。如果我想在三个文件上运行这个,比如样本A、B和C,我会使用类似find的xargs或parallel:
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中使用了一个快速的正则表达式替换来实现这一点。但我希望能够用一句快速的俏皮话做到这一点。
提前谢谢。
我在Perl中用一个快速的正则表达式替换实现了这一点。但我希望能够用一句快速的俏皮话做到这一点。
Perl也有一行代码,就像sed
和awk
一样
find . -name "sample*_1.txt" | perl -pe 's/_1.txt$//' | parallel program {}-out {}_1.txt {}_2.txt
(-e
标志表示"下一个参数是程序文本";-p
标志表示"程序应循环运行;对于每一行输入,将$_
设置为该行,然后运行程序,然后打印$_
"。)
使用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
用三个参数组成命令行。
假设目录中每对总是有两个文件,并且假设它们按find
正确排序(这可以通过find
到sort
的管道结果来确保),那么xargs -l 2
可能会完成这项工作。这个命令告诉xargs
在它执行的每个命令行上放置2个连续的传入参数。
较短的版本:
parallel --xapply program {1.}.out {1} {2} :::: <(ls *_1.txt) <(ls *_2.txt)
但这只适用于每个_1.txt都有匹配的_2.txt的情况,反之亦然。